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@de0fac2e4500dabe0009e67214ff5f5447ce83dd
- name: Install Rust (${{ matrix.toolchain }})
uses: dtolnay/rust-toolchain@f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 with:
toolchain: ${{ matrix.toolchain }}
components: rustfmt, clippy
- name: Cache cargo registry and build outputs
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd - name: Build wheels
uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad 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@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd - name: Build wheels
uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad 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@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd - name: Build wheels
uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad 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@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd - name: Build wheels
uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad 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@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f 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:
id-token: write
contents: write
attestations: write
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c - name: Generate artifact attestation
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 with:
subject-path: 'wheels-*/*'
- name: Publish to PyPI
if: ${{ startsWith(github.ref, 'refs/tags/') }}
uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad with:
command: upload
args: --non-interactive --skip-existing wheels-*/*
wasm:
name: wasm-pack build
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
- name: Install Rust (stable)
uses: dtolnay/rust-toolchain@f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 with:
toolchain: stable
- name: Install wasm-pack
run: cargo install wasm-pack --locked
- name: Cache cargo registry and build outputs
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 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@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f with:
name: js-packages
path: dist/js
wasm-release:
name: Release wasm package
runs-on: ubuntu-latest
if: ${{ startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' }}
needs: wasm
permissions:
contents: write
attestations: write
id-token: write
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
- name: Generate artifact attestation
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 with:
subject-path: 'js-packages/**/*'
- name: Tree
run: |
tree js-packages
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f 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
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 ext: ""
asset_name: jsoncompat-macos-x86_64
- os: macos-latest 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd
- name: Install Rust (stable)
uses: dtolnay/rust-toolchain@f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 with:
toolchain: stable
- name: Cache cargo registry and build outputs
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 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: Run CLI demo
if: ${{ matrix.os == 'ubuntu-latest' }}
run: ./target/release/jsoncompat 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@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f with:
name: cli-${{ matrix.os }}
path: dist/${{ matrix.asset_name }}
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@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
- name: Generate artifact attestation
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 with:
subject-path: 'cli-*/**'
- name: Upload binaries to GitHub Release
if: ${{ startsWith(github.ref, 'refs/tags/') }}
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
shopt -s nullglob
tag="${GITHUB_REF_NAME}"
assets=(cli-*/*)
if (( ${#assets[@]} == 0 )); then
echo "No release assets matched cli-*/*"
exit 1
fi
if gh release view "$tag" >/dev/null 2>&1; then
gh release upload "$tag" "${assets[@]}" --clobber
else
gh release create "$tag" "${assets[@]}" --verify-tag --title "$tag" --notes ""
fi