jsoncompat 0.3.0

JSON Schema Compatibility Checker
Documentation
name: CI

on:
  push:
    branches: [main]
  pull_request:
  workflow_dispatch:

jobs:
  rust:
    name: ${{ matrix.os }} / ${{ matrix.toolchain }}
    runs-on: ${{ matrix.os }}

    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
        toolchain: [stable, beta, nightly]

    env:
      RUSTFLAGS: "-D warnings"

    steps:
      - name: Checkout sources
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

      - name: Install Rust (${{ matrix.toolchain }})
        uses: dtolnay/rust-toolchain@f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 # stable
        with:
          toolchain: ${{ matrix.toolchain }}
          components: rustfmt, clippy

      - name: Cache cargo registry and build outputs
        uses: actions/cache@2f8e54208210a422b2efd51efaa6bd6d7ca8920f # v3.4.3
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-${{ matrix.toolchain }}-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: |
            ${{ runner.os }}-${{ matrix.toolchain }}-

      - name: rustfmt (check only)
        run: cargo fmt --all -- --check

      - name: Clippy (deny warnings)
        run: cargo clippy --workspace --all-features --all-targets -- -D warnings

      - name: cargo check
        run: cargo check --workspace --all-features --all-targets --locked

      - name: cargo test
        run: cargo test --workspace --all-features --all-targets --locked

  python-linux:
    runs-on: ${{ matrix.platform.runner }}
    strategy:
      matrix:
        platform:
          - runner: ubuntu-22.04
            target: x86_64
          - runner: ubuntu-22.04
            target: aarch64

    steps:
      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
      - name: Build wheels
        uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
        with:
          target: ${{ matrix.platform.target }}
          args: --release --out dist -i '3.11 3.12 3.13'
          sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
          manylinux: auto
          working-directory: python
      - name: Upload wheels
        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
        with:
          name: wheels-linux-${{ matrix.platform.target }}
          path: python/dist

  python-musllinux:
    runs-on: ${{ matrix.platform.runner }}
    strategy:
      matrix:
        platform:
          - runner: ubuntu-22.04
            target: x86_64
          - runner: ubuntu-22.04
            target: aarch64
    steps:
      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
      - name: Build wheels
        uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
        with:
          target: ${{ matrix.platform.target }}
          args: --release --out dist -i '3.11 3.12 3.13'
          sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
          manylinux: musllinux_1_2
          working-directory: python
      - name: Upload wheels
        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
        with:
          name: wheels-musllinux-${{ matrix.platform.target }}
          path: python/dist

  python-windows:
    runs-on: ${{ matrix.platform.runner }}
    strategy:
      matrix:
        platform:
          - runner: windows-latest
            target: x64
          - runner: windows-latest
            target: x86
    steps:
      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
      - name: Build wheels
        uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
        with:
          target: ${{ matrix.platform.target }}
          args: --release --out dist -i '3.11 3.12 3.13'
          sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
          working-directory: python
      - name: Upload wheels
        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
        with:
          name: wheels-windows-${{ matrix.platform.target }}
          path: python/dist

  python-macos:
    runs-on: ${{ matrix.platform.runner }}
    strategy:
      matrix:
        platform:
          - runner: macos-15-intel
            target: x86_64
          - runner: macos-latest
            target: aarch64
    steps:
      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
      - name: Build wheels
        uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
        with:
          target: ${{ matrix.platform.target }}
          args: --release --out dist -i '3.11 3.12 3.13'
          sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
          working-directory: python
      - name: Upload wheels
        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
        with:
          name: wheels-macos-${{ matrix.platform.target }}
          path: python/dist

  python-release:
    name: Release
    runs-on: ubuntu-latest
    if: ${{ startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' }}
    needs: [python-linux, python-musllinux, python-windows, python-macos]
    permissions:
      # Use to sign the release artifacts
      id-token: write
      # Used to upload release artifacts
      contents: write
      # Used to generate artifact attestation
      attestations: write
    steps:
      - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
      - name: Generate artifact attestation
        uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0
        with:
          subject-path: 'wheels-*/*'
      - name: Publish to PyPI
        if: ${{ startsWith(github.ref, 'refs/tags/') }}
        uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
        with:
          command: upload
          args: --non-interactive --skip-existing wheels-*/*

# ---------------------------------------------------------------------------
# Build WebAssembly / JavaScript packages -----------------------------------
# ---------------------------------------------------------------------------

  wasm:
    name: wasm-pack build
    runs-on: ubuntu-latest

    steps:
      - name: Checkout sources
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

      - name: Install Rust (stable)
        uses: dtolnay/rust-toolchain@f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 # stable
        with:
          toolchain: stable

      - name: Install wasm-pack
        run: cargo install wasm-pack --locked

      - name: Cache cargo registry and build outputs
        uses: actions/cache@2f8e54208210a422b2efd51efaa6bd6d7ca8920f # v3.4.3
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: wasm-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }}

      - name: Build WebAssembly packages
        run: |
          set -euo pipefail
          for target in bundler nodejs web; do
            echo "--- Building for $target target ---"
            wasm-pack build wasm --release --target "$target" --out-dir "pkg-$target"
          done

      - name: Prepare distribution directory
        run: |
          mkdir -p dist/js
          for target in bundler nodejs web; do
            mkdir -p "dist/js/$target"
            cp -r "wasm/pkg-$target"/* "dist/js/$target/"
            cp wasm/README.md "dist/js/$target/README.md"
          done

      - name: Upload wasm artifacts
        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
        with:
          name: js-packages
          path: dist/js

# ---------------------------------------------------------------------------
# Release WebAssembly package to npm ----------------------------------------
# ---------------------------------------------------------------------------

  wasm-release:
    name: Release wasm package
    runs-on: ubuntu-latest
    if: ${{ startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' }}
    needs: wasm
    permissions:
      # Used to upload release artifacts
      contents: write
      # Used to generate build provenance attestation
      attestations: write
      # Required for provenance signing & publishing to npm
      id-token: write

    steps:
      - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0

      - name: Generate artifact attestation
        uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0
        with:
          subject-path: 'js-packages/**/*'

      - name: Tree
        run: |
          tree js-packages
      - uses: actions/setup-node@v4
        with:
          node-version: '24'
          registry-url: 'https://registry.npmjs.org'

      - name: Publish to npm (tag builds only)
        if: ${{ startsWith(github.ref, 'refs/tags/') }}
        run: |
          set -euo pipefail
          echo "Publishing WebAssembly web package …"
          # for now, only publish the web package
          pushd js-packages/web
          # rename the package to jsoncompat from jsoncompat_wasm
          perl -0777 -pi -e 's/"name"\s*:\s*"jsoncompat_wasm"/"name": "jsoncompat"/' package.json
          npm publish . --access public --provenance
          popd


# ---------------------------------------------------------------------------
# Build Rust CLI binaries ----------------------------------------------------
# ---------------------------------------------------------------------------

  cli:
    name: Build CLI binary
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: ubuntu-latest
            ext: ""
            asset_name: jsoncompat-linux-x86_64
          - os: macos-15-intel # x86_64 runner
            ext: ""
            asset_name: jsoncompat-macos-x86_64
          - os: macos-latest # arm (Apple Silicon)
            ext: ""
            asset_name: jsoncompat-macos-aarch64
          - os: windows-latest
            ext: ".exe"
            asset_name: jsoncompat-windows-x86_64.exe
    runs-on: ${{ matrix.os }}

    steps:
      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

      - name: Install Rust (stable)
        uses: dtolnay/rust-toolchain@f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 # stable
        with:
          toolchain: stable

      - name: Cache cargo registry and build outputs
        uses: actions/cache@2f8e54208210a422b2efd51efaa6bd6d7ca8920f # v3.4.3
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: cli-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }}

      - name: Build CLI
        run: cargo build --locked --release --bin jsoncompat

      - name: Install just
        if: ${{ matrix.os == 'ubuntu-latest' }}
        run: cargo install just --locked --version 1.45.0

      - name: Run CLI demo
        if: ${{ matrix.os == 'ubuntu-latest' }}
        run: just demo -- --noninteractive

      - name: Prepare artifact
        shell: bash
        run: |
          mkdir -p dist
          cp target/release/jsoncompat${{ matrix.ext }} dist/${{ matrix.asset_name }}

      - name: Upload CLI artifact
        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
        with:
          name: cli-${{ matrix.os }}
          path: dist/${{ matrix.asset_name }}

# ---------------------------------------------------------------------------
# Release Rust CLI binaries to GitHub Releases ------------------------------
# ---------------------------------------------------------------------------

  cli-release:
    name: Release CLI binaries
    if: ${{ startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' }}
    runs-on: ubuntu-latest
    needs: cli
    permissions:
      contents: write
      attestations: write
      id-token: write

    steps:
      - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0

      - name: Generate artifact attestation
        uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0
        with:
          subject-path: 'cli-*/**'

      - name: Upload binaries to GitHub Release
        if: ${{ startsWith(github.ref, 'refs/tags/') }}
        uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8 # v2.3.2
        with:
          files: cli-*/**