Keep diagrams in sync in CI
How to fail a pull request whose diagram pictures no longer match their source, with the GitHub Action or the command line. It is for anyone who keeps Plotwork diagrams in Markdown or .diagram files in a repository.
- GitHub Actions
- GitHub
TL;DR
| Question | Answer |
|---|---|
| What is checked? | Every diagram fence in the files you name: a fence with no picture under it, a picture whose source or renderer changed, and source with mistakes. .diagram files are checked for mistakes. |
| What runs the check on GitHub? | The action plotwork-official/plotwork-action, pinned by commit. The engine is bundled into it, so it installs nothing and needs no account, key, or token. |
| How does a failure show in a pull request? | Each stale fence and each mistake is an error annotation on its line in the Files changed tab, and the job summary lists the files with the command that fixes them. |
| How do I fix a failure? | Run the action with command: sync on the same files and commit the Markdown and the SVGs it writes, or run npx -y @buun_group/plotwork@0.1.0-beta.13 sync on your machine. |
| What else can the action do? | sync redraws in the workspace and commits nothing, validate reports mistakes only, render draws .diagram files to SVG, and generate makes diagrams from Terraform, OpenAPI, Compose and other files and fails or opens a pull request when they drift (section 5). |
| What about other CI? | The command line runs the same check: npx -y @buun_group/plotwork@0.1.0-beta.13 sync --check "docs/**/*.md". See CI usage. |
| Does the check send my diagrams anywhere? | No. The action and the command line count nothing and, by default, make no request. Either can read an organisation's saved style rules when you name the organisation, and generate in write mode talks to GitHub to push and open a pull request, and to Plotwork only with publish: true. Both read your repository settings file on the machine they run on. |
1. Check every pull request
Copy this workflow to .github/workflows/plotwork.yml:
name: plotwork
on: pull_request: paths: ['**/*.md', '**/*.diagram']
permissions: contents: read
jobs: diagrams: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 with: persist-credentials: false - uses: plotwork-official/plotwork-action@dcec4036897b73bd3ea724b3991f4fd0ac880757 # v1.0.0-beta.14 with: paths: | README.md docs/**/*.mdThe samples pin the latest release of the Action by its commit. @v1 becomes available at the first stable release.
With no paths, the action reads every Markdown file in the repository. A line in paths that starts with ! leaves out what it matches, such as !docs/drafts/**. Pin actions/checkout to a full commit SHA too, as you would any third-party action.
A stale diagram looks like this in the log, and as an error on line 12 of the file in the pull request:
::error file=docs/architecture.md,line=12,title=Stale diagram::The picture under this diagram is missing or out of date.%0AFix: run plotwork-official/plotwork-action@v1.0.0-beta.14 with command: sync, then commit the Markdown file and the SVG files.The job summary gives the same fix: run the action with command: sync and the same paths, then commit what it wrote. Once the command line is on npm, the summary and the annotation also give an npx command that pins the version built from the same engine as the action, so the pictures it draws pass the check.
2. The commands
command | Reads | Writes | Fails when |
|---|---|---|---|
check (default) | paths and diagrams | Nothing | A picture is missing or stale, or a diagram has an error |
sync | paths | The Markdown files and their SVGs, in the workspace | A diagram has an error |
validate | paths and diagrams | Nothing | A diagram has an error, or a warning with fail-on: warning |
render | diagrams | A light and a dark SVG per .diagram file, in out-dir | A diagram has an error |
generate | The sources of the settings file | Nothing with mode: check; with mode: write, the diagrams, then a pull request or a commit | A diagram drifted from its files (check mode), or a diagram has an error |
Redraw and open a pull request
sync redraws the stale pictures in the runner's workspace and commits nothing; it never holds a token. To commit from a workflow, give the write permissions to the job and add a step that commits, such as peter-evans/create-pull-request:
name: plotwork-sync
on: push: branches: [main] paths: ['**/*.md']
permissions: contents: read
jobs: sync: runs-on: ubuntu-latest permissions: contents: write pull-requests: write steps: - uses: actions/checkout@v7 with: persist-credentials: false - id: plotwork uses: plotwork-official/plotwork-action@dcec4036897b73bd3ea724b3991f4fd0ac880757 # v1.0.0-beta.14 with: command: sync paths: docs/**/*.md - if: steps.plotwork.outputs.stale != '0' uses: peter-evans/create-pull-request@v8 with: branch: plotwork/sync commit-message: 'docs: redraw stale diagrams' title: 'docs: redraw stale diagrams' add-paths: docs/**The repository must allow GitHub Actions to create pull requests (Settings, Actions, General). Most teams keep check on pull requests and run the sync locally.
Report mistakes only
- uses: plotwork-official/plotwork-action@dcec4036897b73bd3ea724b3991f4fd0ac880757 # v1.0.0-beta.14 with: command: validate diagrams: diagrams/**/*.diagram fail-on: warningDraw .diagram files
- uses: plotwork-official/plotwork-action@dcec4036897b73bd3ea724b3991f4fd0ac880757 # v1.0.0-beta.14 with: command: render diagrams: diagrams/**/*.diagram out-dir: build/diagramsdiagrams/flow.diagram becomes build/diagrams/diagrams/flow.svg and flow.dark.svg. Each SVG carries its source, so Editing an existing diagram works on it.
3. Inputs and outputs
| Input | Default | Meaning |
|---|---|---|
command | check | check, sync, validate, render, or generate. |
paths | **/*.md | Markdown files: one glob, file, or folder per line. node_modules and .git are never searched. |
diagrams | **/*.diagram | .diagram files, in the same form. Set it to '' for none. |
out-dir | plotwork-svg | Where render writes, inside the repository. |
fail-on | error | error, warning, or never. Problems are annotated either way. |
convert-mermaid | false | When true, check and sync treat each mermaid fence that converts as a diagram. See Migrating from Mermaid. |
config | empty | The repository settings: header defaults every command applies, and rules check and validate apply. Empty looks for plotwork.config.json, then .plotwork/config.json, from working-directory up to the repository root; off reads none. |
rules-org | empty | An organisation whose saved style rules to apply instead of the file's rules, read with the key in PLOTWORK_API_KEY. |
mode, on-drift, pr-branch, pr-title, commit-message, publish, github-token | generate only. See Diagrams as code, section 7. | |
summary | true | Write the job summary. |
working-directory | . | The folder to run in. Annotations still name files from the repository root. |
| Output | Meaning |
|---|---|
stale | Diagrams whose picture was missing or out of date. |
errors, warnings | The problems found. |
files | A JSON array: the files that need a sync (check), the files written (sync, render), or the files with an error (validate). |
pull-request, published | generate only: the pull request it opened or edited, and what it published. |
check, validate, and render need only contents: read. generate in check mode does too; in write mode it needs contents: write, and pull-requests: write to open a pull request.
4. The command line
The npm package @buun_group/plotwork holds the bin plotwork, built from the same engine as the action. It runs the same check on any CI, as one command with an exit code:
npx -y @buun_group/plotwork@0.1.0-beta.13 sync --check "docs/**/*.md"Pin the version, so a new release cannot change your build without a change you review. The CLI tab has every command, with the pipeline for GitLab CI, Azure Pipelines, Jenkins, and CircleCI, the exit codes and output formats, and the command reference.
5. Diagrams made from files
When a diagram is made from files of the repository, such as a Terraform stack or an OpenAPI document, name it in sources in the settings file, and let generate keep it in step. The full guide is Diagrams as code.
A pull request check
name: diagrams
on: pull_request:
permissions: contents: read
jobs: drift: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 with: persist-credentials: false - uses: plotwork-official/plotwork-action@dcec4036897b73bd3ea724b3991f4fd0ac880757 # v1.0.0-beta.14 with: command: generateRegenerate on main and open a pull request
name: diagrams-regenerate
on: push: branches: [main] schedule: - cron: '0 4 * * *'
permissions: contents: read
jobs: regenerate: runs-on: ubuntu-latest permissions: contents: write pull-requests: write steps: - uses: actions/checkout@v7 - uses: plotwork-official/plotwork-action@dcec4036897b73bd3ea724b3991f4fd0ac880757 # v1.0.0-beta.14 with: command: generate mode: writeThe repository must allow GitHub Actions to create pull requests (Settings, Actions, General). A pull request opened with the workflow's own token starts no workflow; pass a GitHub App or personal token in github-token to have its checks run.
Publish to an organisation
name: diagrams-publish
on: push: branches: [main]
permissions: contents: read
jobs: publish: runs-on: ubuntu-latest permissions: contents: write pull-requests: write steps: - uses: actions/checkout@v7 - uses: plotwork-official/plotwork-action@dcec4036897b73bd3ea724b3991f4fd0ac880757 # v1.0.0-beta.14 with: command: generate mode: write publish: true env: PLOTWORK_API_KEY: ${{ secrets.PLOTWORK_API_KEY }}Each source with a publish section, such as { "organization": "acme", "folder": "Platform" }, is published with the organisation key in the secret. Only the generated diagram source is sent, never the files it was made from.
See also
| Page | Why |
|---|---|
| Markdown and GitHub | What a sync writes and why the pictures are committed |
| Migrating from Mermaid | Convert existing Mermaid fences first |
| Repository settings | Defaults for every header, and rules a pull request must pass |
| Diagrams as code | Diagrams made from Terraform, OpenAPI, Compose and other files, kept in step |
| Slack, email, Confluence, and Notion | Share a picture outside the repository |
| Local usage sharing | What the MCP package can count, which the command line and the action never do |