Skip to content

GitHub Actions Integration

Automate your Markdown updates with CI/CD workflows.

Continuous Integration with GitHub Actions

You can use markdown-code-runner to automatically update your Markdown files in a CI environment. The following example demonstrates how to configure a GitHub Actions workflow that updates your README.md whenever changes are pushed to the main branch.

  1. Create a new workflow file in your repository at .github/workflows/markdown-code-runner.yml.

  2. Add the following content to the workflow file:

name: Update README.md

on:
  push:
    branches:
      - main
  pull_request:

jobs:
  update_readme:
    runs-on: ubuntu-latest
    steps:
      - name: Check out repository
        uses: actions/checkout@v6
        with:
          persist-credentials: false
          fetch-depth: 0

      - name: Set up Python
        uses: actions/setup-python@v6
        with:
          python-version: "3.14.2"

      - name: Install uv
        uses: astral-sh/setup-uv@v7

      - name: Install markdown-code-runner
        run: |
          uv venv
          uv pip install markdown-code-runner

      # Install dependencies you're using in your README.md
      - name: Install other Python dependencies
        run: |
          uv pip install pandas tabulate pytest matplotlib requests

      # Rust is only needed for an example in our README.md
      - uses: actions-rust-lang/setup-rust-toolchain@v1

      - name: Run update-readme.py
        run: uv run markdown-code-runner --verbose README.md

      - name: Commit updated README.md
        id: commit
        run: |
          git add README.md
          git config --local user.email "github-actions[bot]@users.noreply.github.com"
          git config --local user.name "github-actions[bot]"
          if git diff --quiet && git diff --staged --quiet; then
            echo "No changes in README.md, skipping commit."
            echo "commit_status=skipped" >> $GITHUB_ENV
          else
            git commit -m "Update README.md"
            echo "commit_status=committed" >> $GITHUB_ENV
          fi

      - name: Push changes
        if: env.commit_status == 'committed'
        uses: ad-m/github-push-action@master
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          branch: ${{ github.head_ref }}
  1. Commit and push the workflow file to your repository. The workflow will now automatically run whenever you push changes to the main branch, updating your README.md with the latest outputs from your code blocks.

For more information on configuring GitHub Actions, check out the official documentation.

Workflow Breakdown

Trigger Events

The workflow triggers on:

  • Push to main: Update documentation when changes are merged
  • Pull requests: Validate documentation changes in PRs

Key Steps

  1. Checkout: Clone the repository with full history for proper git operations
  2. Python Setup: Configure Python environment
  3. Install Dependencies: Install markdown-code-runner and any packages used in your code blocks
  4. Run Processing: Execute markdown-code-runner on your Markdown files
  5. Commit & Push: Automatically commit any changes

Advanced Configurations

Processing Multiple Files

To process multiple Markdown files, create a helper script using PEP 723 inline script dependencies:

#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.10"
# dependencies = ["markdown-code-runner"]
# ///
"""Update all markdown files that use markdown-code-runner."""
from pathlib import Path

from markdown_code_runner import update_markdown_file


def find_markdown_files(root: Path) -> list[Path]:
    """Find all markdown files containing code markers."""
    files = []
    for md_file in root.rglob("*.md"):
        content = md_file.read_text()
        if "<!-- CODE:START -->" in content:
            files.append(md_file)
    return sorted(files)


def main():
    root = Path(".")
    files = find_markdown_files(root / "docs")

    # Also check README
    readme = root / "README.md"
    if readme.exists() and "<!-- CODE:START -->" in readme.read_text():
        files.append(readme)

    for f in files:
        print(f"Processing {f}...")
        update_markdown_file(f)


if __name__ == "__main__":
    main()

Run it with uv run update_docs.py or make it executable and run directly.

Only Run on Specific Files

Limit when the workflow runs:

on:
  push:
    branches: [main]
    paths:
      - 'docs/**/*.md'
      - 'README.md'
      - '.github/workflows/docs.yml'

Troubleshooting

Import Errors

If your code blocks import local modules, ensure they're installed:

- name: Install local package
  run: pip install -e .

Permission Issues

Ensure the workflow has write permissions:

permissions:
  contents: write

Token Issues

For pushing to protected branches, you may need a Personal Access Token:

- name: Push changes
  uses: ad-m/github-push-action@master
  with:
    github_token: ${{ secrets.PAT_TOKEN }}
    branch: ${{ github.ref }}