Integrating Pulsar into CI/CD

Add Pulsar to your GitHub Actions pipeline

This tutorial covers adding Pulsar to your continuous integration pipeline with caching, JSON output, and PR blocking.

Basic GitHub Actions workflow

.github/workflows/ci.yml
name: CI
on: [push, pull_request]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install Pulsar
        run: |
          curl -L https://github.com/CarlosEduJs/pulsar/releases/latest/download/pulsar-cli-x86_64-unknown-linux-gnu.tar.xz | tar xJ
          sudo mv pulsar /usr/local/bin/

      - name: Check with Pulsar
        run: pulsar check src/

This is the simplest setup. On every push and PR, Pulsar downloads and runs against src/.

Caching the binary

Avoid re-downloading on every run by caching the binary:

.github/workflows/ci.yml
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Cache Pulsar binary
        id: cache-pulsar
        uses: actions/cache@v4
        with:
          path: /usr/local/bin/pulsar
          key: pulsar-${{ runner.os }}

      - name: Install Pulsar (if not cached)
        if: steps.cache-pulsar.outputs.cache-hit != 'true'
        run: |
          curl -L https://github.com/CarlosEduJs/pulsar/releases/latest/download/pulsar-cli-x86_64-unknown-linux-gnu.tar.xz | tar xJ
          sudo mv pulsar /usr/local/bin/

      - name: Check with Pulsar
        run: pulsar check src/

The cache key is based on the runner OS. Invalidate the cache manually when you want to force a Pulsar upgrade.

JSON output for custom tooling

Use --format json to pipe diagnostics into jq or custom scripts:

- name: Check with Pulsar (JSON)
  continue-on-error: true
  run: |
    pulsar check src/ --format json > diagnostics.json

- name: Fail if any errors
  run: |
    errors=$(jq '[.[] | select(.severity == "Error")] | length' diagnostics.json)
    if [ "$errors" -gt 0 ]; then
      echo "Found $errors errors"
      exit 1
    fi

The continue-on-error: true flag lets the job continue so the jq step can run. Without it, pulsar check would exit 1 and the remaining steps would be skipped. The jq step still fails the job when errors are present.

Blocking PRs on new violations

Combine with reviewdog or actions/github-script to annotate PRs:

- name: Check with Pulsar (JSON)
  continue-on-error: true
  run: pulsar check src/ --format json > pulsar-report.json

- name: Annotate PR
  uses: actions/github-script@v7
  if: github.event_name == 'pull_request'
  with:
    script: |
      const fs = require('fs');
      const diagnostics = JSON.parse(fs.readFileSync('pulsar-report.json', 'utf8'));

      diagnostics.forEach(d => {
        core.error(d.message, {
          file: d.location.file,
          line: d.location.line,
          title: d.rule_id,
        });
      });

- name: Fail on errors
  run: |
    errors=$(jq 'length' pulsar-report.json)
    if [ "$errors" -gt 0 ]; then
      echo "Pulsar found $errors diagnostic(s)"
      exit 1
    fi

The continue-on-error: true flag allows the job to continue past the check step so annotations can be created. The final step ensures the job still fails the PR when diagnostics exist.

Matrix builds (multi-OS)

jobs:
  lint:
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4

      - name: Install Pulsar
        run: |
          case "${{ runner.os }}" in
            Linux)
              url="https://github.com/CarlosEduJs/pulsar/releases/latest/download/pulsar-cli-x86_64-unknown-linux-gnu.tar.xz"
              ;;
            macOS)
              url="https://github.com/CarlosEduJs/pulsar/releases/latest/download/pulsar-cli-aarch64-apple-darwin.tar.xz"
              ;;
          esac
          curl -L "$url" | tar xJ
          sudo mv pulsar /usr/local/bin/

      - name: Check with Pulsar
        run: pulsar check src/

GitLab CI

.gitlab-ci.yml
pulsar-check:
  stage: lint
  image: ubuntu:latest
  script:
    - apt-get update && apt-get install -y curl xz-utils
    - curl -L https://github.com/CarlosEduJs/pulsar/releases/latest/download/pulsar-cli-x86_64-unknown-linux-gnu.tar.xz | tar xJ
    - mv pulsar /usr/local/bin/
    - pulsar check src/
  only:
    - merge_requests

Best practices

PracticeWhy
Cache the binarySave 15-30s per run
Run on PRs onlyAvoid wasting CI minutes on every push to WIP branches
Use --format json in CIEasier to parse, annotate, and forward to monitoring
Keep pulsar.toml in version controlEnsures consistent rules across machines
Run Pulsar before testsFail fast — no point running tests if the code has schema mismatches

Last updated on

On this page