Skip to content
Connect an agent
Use the CLI

Command line in CI

The pipeline step that fails a build when a diagram picture is stale or a generated diagram has drifted, for GitHub Actions, GitLab CI, Azure Pipelines, Jenkins, and CircleCI. Each runs the pinned release with npx, so the job installs nothing beyond Node 22.

For
  • GitHub Actions
  • GitLab

TL;DR

QuestionAnswer
Which check do I run?sync --check for the pictures under diagram fences. Add generate --check when diagrams are made from Terraform, OpenAPI or other files, and check when the repository has style rules.
What fails the job?Exit code 1 for a problem in a diagram, 2 for a mistake in the command. Both fail a step in every CI system.
Does it need a key or a token?No. Only check --org reads a key, from PLOTWORK_API_KEY.
Does it send my diagrams anywhere?No. The check reads the checked-out files and writes nothing.
On GitHub, should I use this or the Action?Either. The GitHub Action runs the same engine without Node and adds a job summary. The command line is the same step on every other CI.
How do I fix a failure?Run npx -y @buun_group/plotwork@0.1.0-beta.13 sync on the same files, then commit the Markdown and the SVGs it wrote.

Every sample pins the release. Move the pin in a change you review, and run sync in the same change, so the pictures are drawn by the release the check runs.

The commands

StepCommandFails when
Picturesnpx -y @buun_group/plotwork@0.1.0-beta.13 sync --check "**/*.md"A picture is missing or stale, or a diagram has a mistake
Generated diagramsnpx -y @buun_group/plotwork@0.1.0-beta.13 generate --checkA diagram drifted from the files it is made from
Style rulesnpx -y @buun_group/plotwork@0.1.0-beta.13 check "**/*.md"A rule at level error is broken

generate --check exits 2 when the settings have no sources, so add its step only to a repository that makes diagrams from files. check exits 2 when there are no rules, in the same way.

"**/*.md" never looks in node_modules, .git, or build output. Narrow it to the folders that hold diagrams, such as README.md "docs/**/*.md", on a large repository.

generate --check --since <ref> checks only the sources whose files changed since that ref, which keeps a large repository's check short. The job needs the history up to the ref: fetch it in the checkout step.

GitHub Actions

yaml
name: diagrams
on:  pull_request:    paths: ['**/*.md', '**/*.diagram', 'plotwork.config.json']
permissions:  contents: read
jobs:  diagrams:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v7        with:          persist-credentials: false      - uses: actions/setup-node@v6        with:          node-version: 22      - run: npx -y @buun_group/plotwork@0.1.0-beta.13 sync --check --format github "**/*.md"

--format github prints each stale fence and each mistake as an annotation on its line of the pull request. To report drift to code scanning, add a step that runs generate --check --format sarif --out plotwork.sarif with if: always(), then uploads the file with github/codeql-action/upload-sarif.

GitLab CI

yaml
diagrams:  image: node:22  rules:    - if: $CI_PIPELINE_SOURCE == "merge_request_event"  script:    - npx -y @buun_group/plotwork@0.1.0-beta.13 sync --check "**/*.md"    - npx -y @buun_group/plotwork@0.1.0-beta.13 generate --check --format junit --out plotwork-junit.xml  artifacts:    when: always    reports:      junit: plotwork-junit.xml

The JUnit report shows each generated diagram as a test in the merge request, failed when it drifted.

Azure Pipelines

yaml
trigger: nonepr:  branches:    include: [main]
pool:  vmImage: ubuntu-latest
steps:  - task: NodeTool@0    inputs:      versionSpec: '22.x'  - script: npx -y @buun_group/plotwork@0.1.0-beta.13 sync --check "**/*.md"    displayName: Diagram pictures are current  - script: npx -y @buun_group/plotwork@0.1.0-beta.13 generate --check --format junit --out $(Build.ArtifactStagingDirectory)/plotwork-junit.xml    displayName: Generated diagrams have not drifted  - task: PublishTestResults@2    condition: always()    inputs:      testResultsFormat: JUnit      testResultsFiles: $(Build.ArtifactStagingDirectory)/plotwork-junit.xml

Jenkins

groovy
pipeline {  agent { docker { image 'node:22' } }  stages {    stage('Diagrams') {      steps {        sh 'npx -y @buun_group/plotwork@0.1.0-beta.13 sync --check "**/*.md"'        sh 'npx -y @buun_group/plotwork@0.1.0-beta.13 generate --check --format junit --out plotwork-junit.xml'      }    }  }  post {    always {      junit allowEmptyResults: true, testResults: 'plotwork-junit.xml'    }  }}

CircleCI

yaml
version: 2.1
jobs:  diagrams:    docker:      - image: cimg/node:22.20.0    steps:      - checkout      - run: npx -y @buun_group/plotwork@0.1.0-beta.13 sync --check "**/*.md"      - run: mkdir -p reports && npx -y @buun_group/plotwork@0.1.0-beta.13 generate --check --format junit --out reports/plotwork-junit.xml      - store_test_results:          path: reports
workflows:  diagrams:    jobs:      - diagrams

Other CI systems

Any system that runs a command and reads its exit code runs the check: install Node 22, then run the command. Exit code 0 passes; 1 and 2 fail. For a runner with no access to the npm registry, mirror the package into your own registry or cache, as you would any other dependency. It is one file with no dependencies to fetch, and the checks make no request.

See also

DocWhy
Keep diagrams in sync in CIThe GitHub Action, its inputs, and opening a pull request with the redrawn pictures
Diagrams as codeSources, overrides, and the drift check
Exit codes and output formatsWhat github, json, sarif, and junit print
Enterprise rolloutReusable workflows, required checks, and air-gapped runners