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
- In your GitHub repo, open Settings → Secrets and variables → Actions.
- Create a secret named
MELDOC_TOKENwith 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.