Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 4 additions & 15 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,26 +1,15 @@
version: 2
updates:
# Enable version updates for Cargo (main crate)
# Enable version updates for Cargo (main crate and fuzz crate)
- package-ecosystem: "cargo"
directory: "/"
schedule:
interval: "monthly"
open-pull-requests-limit: 10
labels:
- "dependencies"
commit-message:
prefix: "deps"
include: "scope"

# Enable version updates for Cargo (fuzz crate)
- package-ecosystem: "cargo"
directory: "/fuzz"
directories:
- "/"
- "/fuzz"
schedule:
interval: "monthly"
open-pull-requests-limit: 10
labels:
- "dependencies"
- "fuzzing"
commit-message:
prefix: "deps"
include: "scope"
Expand Down
81 changes: 65 additions & 16 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,52 @@ on:

env:
CARGO_TERM_COLOR: always
MSRV: '1.90'

jobs:
test:
name: Test Suite
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
rust-version: ['1.90', 'stable']
features:
- ''
- 'scheme'
- 'jsonlogic'
- 'scheme,jsonlogic'
rust-version: ['msrv', 'stable']
cargo-args:
- '--no-default-features'
- '--no-default-features --features scheme'
- '--no-default-features --features jsonlogic'
- '--no-default-features --features scheme,jsonlogic'

steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Resolve toolchain
id: resolve
shell: bash
run: |
rust="${{ matrix.rust-version }}"
[[ "$rust" == "msrv" ]] && rust="$MSRV"
echo "toolchain=$rust" >> "$GITHUB_OUTPUT"

- name: Install Rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust-version }}
toolchain: ${{ steps.resolve.outputs.toolchain }}

- name: Install clippy (stable only)
if: matrix.rust-version == 'stable'
run: rustup component add clippy

- name: Cache dependencies
uses: Swatinem/rust-cache@v2

- name: Run tests
run: cargo test --features="${{ matrix.features }}" --verbose
run: cargo test --all-targets ${{ matrix.cargo-args }} --verbose

- name: Run clippy
if: matrix.rust-version == 'stable'
run: cargo clippy --all-targets ${{ matrix.cargo-args }} -- -D warnings

- name: Run doc tests (all features)
run: cargo test --doc --all-features
Expand All @@ -60,7 +78,9 @@ jobs:
uses: taiki-e/install-action@cargo-llvm-cov

- name: Generate code coverage
run: cargo llvm-cov --all-features --workspace --html --output-dir coverage-html
run: |
cargo llvm-cov --all-features --workspace --html --output-dir coverage-html
cargo llvm-cov --all-features --workspace --lcov --output-path lcov.info --no-run

- name: Upload coverage HTML
uses: actions/upload-artifact@v7
Expand All @@ -69,8 +89,16 @@ jobs:
path: coverage-html/
retention-days: 30

lint:
name: Linting
- name: Upload to Codecov
uses: codecov/codecov-action@v5
with:
files: lcov.info
fail_ci_if_error: true
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

fmt:
name: Formatting
runs-on: ubuntu-latest

steps:
Expand All @@ -80,17 +108,14 @@ jobs:
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
components: rustfmt

- name: Cache dependencies
uses: Swatinem/rust-cache@v2

- name: Check formatting
run: cargo fmt --all -- --check

- name: Run clippy
run: cargo clippy --all-targets --all-features -- -D warnings

docs:
name: Documentation
runs-on: ubuntu-latest
Expand Down Expand Up @@ -142,7 +167,31 @@ jobs:
uses: actions/checkout@v6

- name: Install cargo-audit
run: cargo install cargo-audit
uses: taiki-e/install-action@v2
with:
tool: cargo-audit

- name: Run security audit
run: cargo audit

minimal-versions:
name: Minimal Versions
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Install Rust nightly
uses: dtolnay/rust-toolchain@nightly

- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable

- name: Install cargo-hack and cargo-minimal-versions
uses: taiki-e/install-action@v2
with:
tool: cargo-hack,cargo-minimal-versions

- name: Check minimal versions
run: cargo +nightly minimal-versions check --direct --all-features
15 changes: 15 additions & 0 deletions .github/workflows/fuzz.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ jobs:
fuzz:
name: Fuzz Testing
runs-on: ubuntu-latest
permissions:
contents: read # to checkout the repo
issues: write # to create/comment on issues
# Only run fuzzing for non-fork repositories to save folks CI credits.
if: github.event.repository.fork == false
strategy:
Expand All @@ -38,6 +41,18 @@ jobs:
- name: Cache dependencies
uses: Swatinem/rust-cache@v2

# Corpus caching:
# - Save key uses run_id so each run creates a new cache (caches are immutable)
# - Restore key uses prefix match to find the most recent cache from any prior run
# - Daily runs ensure we always have a recent corpus to build on
- name: Restore corpus cache
uses: actions/cache@v4
with:
path: fuzz/corpus/${{ matrix.target }}
key: fuzz-corpus-${{ matrix.target }}-${{ github.run_id }}
restore-keys: |
fuzz-corpus-${{ matrix.target }}-

- name: Run fuzzer
run: |
DURATION=${{ github.event.inputs.duration || '300' }}
Expand Down
40 changes: 23 additions & 17 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
# so tags in forks don't create upstream-style releases.
if: github.event.repository.fork == false
outputs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
tag_name: ${{ steps.tag_name.outputs.TAG_NAME }}

steps:
- name: Checkout code
Expand All @@ -29,6 +29,14 @@ jobs:
id: tag_name
run: echo "TAG_NAME=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT

- name: Verify tag is on main
run: |
git fetch origin main
if ! git merge-base --is-ancestor $GITHUB_SHA origin/main; then
echo "Error: Tag must point to a commit on the main branch"
exit 1
fi

- name: Verify version matches tag
run: |
TAG_VERSION=${GITHUB_REF#refs/tags/v}
Expand All @@ -40,22 +48,19 @@ jobs:
echo "Version check passed: $CARGO_VERSION"

- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ steps.tag_name.outputs.TAG_NAME }}
release_name: Release ${{ steps.tag_name.outputs.TAG_NAME }}
draft: false
prerelease: false
GH_TOKEN: ${{ github.token }}
run: gh release create ${{ steps.tag_name.outputs.TAG_NAME }} --title "Release ${{ steps.tag_name.outputs.TAG_NAME }}" --generate-notes

publish-crate:
name: Publish to crates.io
runs-on: ubuntu-latest
# crates.io publishing is only meaningful for non-fork roots
if: github.event.repository.fork == false
needs: create-release
environment: crates-io
permissions:
id-token: write # Required for OIDC trusted publishing

steps:
- name: Checkout code
Expand All @@ -67,8 +72,14 @@ jobs:
- name: Cache dependencies
uses: Swatinem/rust-cache@v2

- name: Authenticate with crates.io
uses: rust-lang/crates-io-auth-action@v1
id: auth

- name: Publish to crates.io
run: cargo publish --all-features --token ${{ secrets.CRATES_IO_TOKEN }}
run: cargo publish --all-features
env:
CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}

build-binaries:
name: Build Release Binaries
Expand Down Expand Up @@ -126,11 +137,6 @@ jobs:
tar -czf ${{ matrix.archive_name }} -C staging .

- name: Upload Release Asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.upload_url }}
asset_path: ./${{ matrix.archive_name }}
asset_name: ${{ matrix.archive_name }}
asset_content_type: application/octet-stream
GH_TOKEN: ${{ github.token }}
run: gh release upload ${{ needs.create-release.outputs.tag_name }} ./${{ matrix.archive_name }}
86 changes: 86 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## 0.3.1

### Added

- Code coverage reporting in CI with Codecov integration
- Maintainer's guide (`docs/MAINTAINERS-GUIDE.md`)
- README facelift

### Changed

- Release process switched to OIDC
- Improved CI pipeline performance with cached tool binaries
- Simplified dependabot configuration
- Fuzzing runs carry over corpus data between runs
- Dependency updates
- Check for cargo minimum dependency versions

### Fixed

- Code coverage improved from 93% to 97%

## 0.3.0

### Added

- Performance benchmarks in CI with criterion with regression detection

### Changed

- **Breaking:** Simplified project module hierarchy
- Benchmark uploads and comments restricted to main branch and PRs
- Clippy clean when not all features are enabled
- Updated dependencies

## 0.2.1

### Added

- Type-safe custom operations registration API (`register_builtin_operation`, `register_variadic_builtin_operation`)
- Iterator-based signatures for list and variadic "rest" parameters
- Project fuzzing support with cargo-fuzz for both S-expression and JSONLogic parsing/evaluation
- Daily fuzzing CI workflow
- Release binary packaging as zip/tar.gz
- Release version verification against git tag
- `.gitattributes` for standardized newline handling

### Changed

- Builtin functions migrated to new type-safe mechanics
- Eliminated `.expect()` calls by construction

### Fixed

- Disabled release tasks on forks

## 0.1.2

### Added

- Official JSONLogic.com conformance test suite
- GitHub CI pipeline
- Dependabot configuration

## 0.1.1

### Changed

- Added docs.rs metadata to build documentation with all features enabled

## 0.1.0

### Added

- Mini Scheme interpreter with integer-only arithmetic and strict typing/booleans
- JSONLogic interpreter with integer-only arithmetic, no nulls, and strict typing/booleans
- Precompiled operations, parse-time arity validation, and stack overflow guards
- Registration of new builtins.
- Sample REPL

Loading