name: CI
on:
push:
branches: [main]
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: 0
RUST_BACKTRACE: 1
jobs:
fmt:
name: rustfmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- run: cargo fmt --all --check
clippy:
name: clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- uses: Swatinem/rust-cache@v2
- run: cargo clippy --locked --all-features --all-targets -- -D warnings
test:
name: test (${{ matrix.toolchain }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
toolchain: [stable, "1.90"]
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.toolchain }}
- uses: Swatinem/rust-cache@v2
- run: cargo test --locked --all-features --all-targets
- run: cargo test --locked --all-features --doc
test-unlocked:
name: test (updated dependencies)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- run: cargo update
- run: cargo test --all-features --all-targets
test-non-utc:
name: test (non-UTC timezone)
runs-on: ubuntu-latest
env:
TZ: Pacific/Auckland
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- run: cargo test --locked --all-features --all-targets
no-std:
name: no_std build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
with:
targets: thumbv7em-none-eabihf
- uses: Swatinem/rust-cache@v2
- run: cargo check --locked --target thumbv7em-none-eabihf --no-default-features
- run: cargo check --locked --target thumbv7em-none-eabihf --all-features
doc:
name: doc
runs-on: ubuntu-latest
env:
RUSTDOCFLAGS: -D warnings
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- run: cargo doc --locked --all-features --no-deps
deny:
name: cargo-deny
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: taiki-e/install-action@cargo-deny
- run: cargo deny check
package:
name: package
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- run: cargo package --locked
- name: License and notice files are in the package
run: |
set -euo pipefail
list=$(cargo package --locked --list)
for f in LICENSE-APACHE LICENSE-MIT THIRD-PARTY-NOTICES; do
echo "$list" | grep -qx "$f" || { echo "::error::$f missing from packaged crate"; exit 1; }
done
py-lint:
name: python bindings (rustfmt + clippy)
runs-on: ubuntu-latest
defaults:
run:
working-directory: bindings/python
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy, rustfmt
- uses: Swatinem/rust-cache@v2
with:
workspaces: bindings/python
- run: cargo fmt --all --check
- run: cargo clippy --locked --all-targets -- -D warnings
py-test:
name: python (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
defaults:
run:
working-directory: bindings/python
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v6
with:
python-version: "3.10"
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
workspaces: bindings/python
- run: python -m pip install --upgrade pip
- run: pip install . pytest mypy
- run: pytest
- run: mypy
py-wheel:
name: abi3 wheel
runs-on: ubuntu-latest
defaults:
run:
working-directory: bindings/python
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v6
with:
python-version: "3.10"
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
workspaces: bindings/python
- run: pip install maturin abi3audit twine
- run: maturin build --release --locked --out dist
- name: The wheel is abi3, from the declared floor
run: |
python - <<'PY'
import pathlib, re, sys
built = [p.name for p in pathlib.Path("dist").glob("*.whl")]
if len(built) != 1 or not re.search(r"-cp310-abi3-", built[0]):
sys.exit(f"::error::expected one cp310-abi3 wheel, got {built}")
PY
- run: abi3audit --strict dist/*.whl
- run: twine check --strict dist/*
- uses: actions/upload-artifact@v4
with:
name: abi3-wheel
path: bindings/python/dist/*.whl
py-abi3:
name: abi3 wheel on ${{ matrix.python }}
needs: py-wheel
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python }}
- uses: actions/download-artifact@v4
with:
name: abi3-wheel
path: wheel
- run: pip install pytest wheel/*.whl
- run: pytest
working-directory: bindings/python
py-free-threaded:
name: python 3.14 free-threaded
runs-on: ubuntu-latest
defaults:
run:
working-directory: bindings/python
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v6
with:
python-version: "3.14t"
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
workspaces: bindings/python
- run: pip install . pytest
- run: pytest
py-sdist:
name: install from sdist
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- uses: dtolnay/rust-toolchain@stable
- run: pip install maturin pytest twine
- run: maturin sdist --out dist
working-directory: bindings/python
- run: twine check --strict bindings/python/dist/*
- name: Build and test from the sdist alone
run: |
set -euo pipefail
mkdir -p "$RUNNER_TEMP/from-sdist"
tar xzf bindings/python/dist/*.tar.gz -C "$RUNNER_TEMP/from-sdist"
python -m venv "$RUNNER_TEMP/venv"
"$RUNNER_TEMP/venv/bin/pip" install pytest
"$RUNNER_TEMP/venv/bin/pip" install --no-binary fasti-dates bindings/python/dist/*.tar.gz
cd "$RUNNER_TEMP/from-sdist"/fasti_dates-*
"$RUNNER_TEMP/venv/bin/pytest" bindings/python/tests