Documentation

CI/CD Integration

Learn how to publish documentation automatically from CI/CD pipelines.

Before you build one: if your repository is on GitHub, GitHub Sync instead. The server does the same work with no pipeline to maintain and no token to rotate, and it syncs both ways — this page is for the cases that needs, such as another provider, a step of your own before the push, or publishing from somewhere that is not a repository at all.

Quick start

Install the CLI and run meldoc ci — it detects which .meldoc.md files changed and pushes them to the server automatically:

curl -fsSL https://meldoc.io/install.sh | bash -s -- --quiet --force
export PATH="$HOME/.local/bin:$PATH"
meldoc ci --token "$MELDOC_TOKEN"

meldoc ci compares commits using git diff, pushes added or modified documents, and deletes removed ones. No manual scan or pull needed.

How meldoc ci works

In diff mode (default), the command auto-detects the base commit from your CI environment:

Variable CI provider
GITHUB_EVENT_BEFORE GitHub Actions
CI_COMMIT_BEFORE_SHA GitLab CI
BITBUCKET_COMMIT~1 Bitbucket Pipelines

If none are set, falls back to HEAD~1. Override with --base, and the head commit — HEAD by default — with --head.

Before pushing, meldoc ci runs structural validation: duplicate aliases, required fields, parent references. If errors are found, the pipeline exits with code 1 before anything reaches the server. Use --skip-validate to bypass this. Validation runs ahead of the diff, so a repository carrying validation errors fails CI even on a commit that touches no documents at all.

Use --all to push every document instead of only changed ones. With prune: true in Configuration, this also deletes server documents that no longer exist locally.

# Preview what would change
meldoc ci --dry-run

# Push all docs, not just changed
meldoc ci --all

Conflicts in CI are always resolved with the local version — there is nobody to prompt. See Conflict Resolution.

Deleted documents

For every .meldoc.md file the commit removed, meldoc ci resolves the document alias from its cache, or by reading the file’s content at the base commit, and deletes that document from the server. If the alias can’t be determined either way, the file is skipped and the run warns about it.

Several projects in one pipeline

With several projects configured under baseDirs, one run covers the whole commit: the git diff is taken once, and the changed and deleted paths are routed to the project that owns each one. A commit touching two documentation trees is a single publish, not two.

meldoc ci --all --token "$MELDOC_TOKEN"

The run reports the outcome per project and exits non-zero if any of them failed, so a partial failure is visible in the pipeline. One project failing does not stop the others — the summary names which projects were processed and which were not. A path that belongs to no configured project is named in the output rather than silently skipped. Add --project <alias> to restrict the run to a single project. See Several Projects in One Repository.

Flags

Flag Default Description
--token $MELDOC_TOKEN API token
--base auto-detected Base commit for the diff
--head HEAD Head commit for the diff
--all false Push all documents, ignore the diff
--dry-run false Preview without changing anything
--no-assets false Skip asset upload
--force false Push every file, ignoring the cache
--skip-validate false Skip pre-publish validation
--project <alias> all projects Limit the run to one of the projects in baseDirs
--debug false Debug logging

Install the CLI in your pipeline

curl -fsSL https://meldoc.io/install.sh | bash -s -- --quiet
echo "$HOME/.local/bin" >> $GITHUB_PATH

--quiet keeps the output minimal, and the setup wizard only runs in interactive terminals, so nothing waits for input. On runners other than GitHub Actions, put the directory on the PATH yourself with export PATH="$HOME/.local/bin:$PATH".

Pass the token through the MELDOC_TOKEN environment variable, filled from your CI provider’s secret store. Never commit a token to source.

GitHub Actions

Create a workflow file — docs.yml under .github/workflows/ in your repository:

name: Documentation Sync

on:
  push:
    branches: [main]
    paths: ['docs/**/*.meldoc.md']

jobs:
  sync-docs:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Install meldoc CLI
        run: |
          curl -fsSL https://meldoc.io/install.sh | bash -s -- --quiet --force
          echo "$HOME/.local/bin" >> $GITHUB_PATH          

      - name: Publish documentation
        env:
          MELDOC_TOKEN: ${{ secrets.MELDOC_TOKEN }}
        run: meldoc ci

Set up the secret

  1. In your GitHub repo, open Settings → Secrets and variables → Actions.
  2. Create a secret named MELDOC_TOKEN with your Integration Tokens.

GitLab CI

Add to .gitlab-ci.yml:

sync_documentation:
  stage: deploy
  image: alpine:latest
  before_script:
    - apk add --no-cache curl bash git
    - curl -fsSL https://meldoc.io/install.sh | bash -s -- --quiet
    - export PATH="$HOME/.local/bin:$PATH"
  script:
    - meldoc ci
  only:
    - main

Set MELDOC_TOKEN in Settings → CI/CD → Variables (check “Masked”). Set GIT_DEPTH: 0 in the job’s variables so the runner has the history the diff needs.

Bitbucket Pipelines

Add to bitbucket-pipelines.yml:

pipelines:
  branches:
    main:
      - step:
          name: Publish docs
          script:
            - curl -fsSL https://meldoc.io/install.sh | bash -s -- --quiet
            - export PATH="$HOME/.local/bin:$PATH"
            - meldoc ci
          clone:
            depth: full

Set MELDOC_TOKEN as a secured repository variable. clone: depth: full gives the diff the history it needs.

Jenkins

Create a Jenkinsfile:

pipeline {
    agent any

    environment {
        MELDOC_TOKEN = credentials('meldoc-token')
    }

    stages {
        stage('Publish Documentation') {
            steps {
                sh '''
                    curl -fsSL https://meldoc.io/install.sh | bash -s -- --quiet --force
                    export PATH="$HOME/.local/bin:$PATH"
                    meldoc ci --base HEAD~1
                '''
            }
        }
    }
}

Jenkins has no standard environment variable for the previous commit, so pass --base HEAD~1 explicitly.

Docker

To run the CLI from a container image:

FROM alpine:latest
RUN apk add --no-cache curl bash git
RUN curl -fsSL https://meldoc.io/install.sh | bash -s -- --quiet \
    && mv ~/.local/bin/meldoc /usr/local/bin/
ENTRYPOINT ["meldoc"]

Handle exit codes

Code Meaning
0 Success (or no changes)
1 Error
if ! meldoc ci; then
  echo "Documentation sync failed"
  exit 1
fi

Note: In CI, conflicts are resolved automatically — the local version wins — so the run still exits 0.

Cache the binary

For faster builds, cache the Meldoc binary so it isn’t downloaded every run:

# GitHub Actions
- name: Cache meldoc
  uses: actions/cache@v3
  with:
    path: ~/.local/bin/meldoc
    key: meldoc-${{ runner.os }}

- name: Install meldoc CLI
  run: |
    if [ ! -f ~/.local/bin/meldoc ]; then
      curl -fsSL https://meldoc.io/install.sh | bash -s -- --quiet --force
    fi
    echo "$HOME/.local/bin" >> $GITHUB_PATH    

Debug pipeline issues

Remove --quiet from the install and add --debug to the CI command:

meldoc ci --debug

To see what a run would do against a known base, without touching the server:

meldoc ci --dry-run --base HEAD~1

Migrate from a meldoc push pipeline

If your pipeline still scripts the diff itself, meldoc ci replaces it:

Before After
Custom shell diff plus meldoc push $FILES meldoc ci
meldoc scan && meldoc push meldoc ci --all
A separate script for deleted documents Nothing — removed files are detected from the diff

What’s next?

Team Workflow — Set up team collaboration workflows.

Configuration — Configure prune mode and other project settings.

Environment Variables — All environment variables and token priority.