Skip to content
Draft
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
15 changes: 15 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.git
deps
_build
priv
native/ortex/target
.venv
.cache
.ruff_cache
runtime
dist
cover
doc
**/__pycache__
examples/deps
examples/_build
13 changes: 13 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
groups:
actions:
patterns: ['*']
- package-ecosystem: pip
directory: /scripts
schedule:
interval: weekly
41 changes: 41 additions & 0 deletions .github/workflows/audit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Dependency audit
on:
schedule:
- cron: '41 7 * * *'
workflow_dispatch:
workflow_call:
permissions:
contents: read
concurrency:
group: audit-${{ github.ref }}
cancel-in-progress: false
jobs:
audit:
runs-on: ubuntu-24.04
timeout-minutes: 20
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: erlef/setup-beam@54075bcc5e249e4758d363f27d099f55d843f124 # v1.24.1
with:
elixir-version: '1.20.4'
otp-version: '29.1.1'
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: '3.14.10'
- run: make deps setup.audit
- run: make audit
- name: Attach audit summary
if: always()
run: |
if test -f dist/reports/audit.md; then
cat dist/reports/audit.md >> "$GITHUB_STEP_SUMMARY"
fi
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
if: always()
with:
name: dependency-audit
path: dist/reports/
retention-days: 14
if-no-files-found: ignore
200 changes: 200 additions & 0 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
name: Checks
on:
pull_request:
types: [opened, synchronize, reopened, labeled, unlabeled]
push:
branches: [main]
workflow_dispatch:
workflow_call:
inputs:
scope:
type: string
default: pr
permissions:
contents: read
concurrency:
group: checks-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
policy:
runs-on: ubuntu-24.04
timeout-minutes: 5
outputs:
matrix: ${{ steps.matrix.outputs.value }}
scope: ${{ steps.matrix.outputs.scope }}
alpine: ${{ steps.matrix.outputs.alpine }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: '3.14.10'
- id: matrix
env:
SCOPE: ${{ inputs.scope || (github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'ci:full') && 'pr' || 'full') }}
run: |
python scripts/ci.py policy
{
echo "value=$(python scripts/ci.py matrix --scope "$SCOPE")"
echo "scope=$SCOPE"
echo "alpine=$(python scripts/ci.py matrix --scope alpine)"
} >> "$GITHUB_OUTPUT"
hygiene:
runs-on: ubuntu-24.04
timeout-minutes: 25
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: erlef/setup-beam@54075bcc5e249e4758d363f27d099f55d843f124 # v1.24.1
with:
elixir-version: '1.20.4'
otp-version: '29.1.1'
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: '3.14.10'
- uses: jdx/mise-action@6be3c7ed4c21d4f76b208d351d95aac273ebb76d # v5.2.4
with:
version: '2026.10.23'
install_args: actionlint shellcheck shfmt
cache: false
add_shims_to_path: false
- name: Prepare checkers
run: |
make setup.rust
python -m venv .venv
.venv/bin/python -m pip install -r scripts/requirements.txt
make deps
- run: make lint test.tooling docs
source:
needs: policy
name: ${{ matrix.id }}
runs-on: ${{ matrix.os }}
timeout-minutes: 30
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.policy.outputs.matrix) }}
defaults:
run:
shell: bash
env:
MIX_ENV: test
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: erlef/setup-beam@54075bcc5e249e4758d363f27d099f55d843f124 # v1.24.1
with:
elixir-version: ${{ matrix.elixir }}
otp-version: ${{ matrix.otp }}
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: '3.14.10'
- name: Select runtime and Nx boundary
env:
RUNTIME: ${{ matrix.runtime }}
NX_MODE: ${{ matrix.nx }}
run: |
python scripts/install_runtime.py install --version "$RUNTIME"
python scripts/ci.py nx "$NX_MODE"
if [[ "$NX_MODE" == locked ]]; then
mix deps.get --check-locked
else
mix deps.update nx
mix deps.get
fi
- name: Validate library, model, system, and package suites
run: |
mix compile --warnings-as-errors
make test test.models test.system test.package
- name: Render library coverage
if: matrix.id == 'linux-current'
run: |
make coverage
cat cover/summary.md >> "$GITHUB_STEP_SUMMARY"
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
if: always()
with:
name: reports-${{ matrix.id }}
path: |
cover/
dist/reports/
retention-days: 14
if-no-files-found: ignore
- name: Assemble native target archive
env:
TARGET: ${{ matrix.target }}
run: python scripts/package.py nif --target "$TARGET"
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
if: needs.policy.outputs.scope == 'full' && matrix.nx == 'locked'
with:
name: nif-${{ matrix.target }}
path: dist/*-${{ matrix.target }}.tar.gz
retention-days: 14
if-no-files-found: error
msrv:
runs-on: ubuntu-24.04
timeout-minutes: 15
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Check the declared minimum Rust version
working-directory: native/ortex
run: |
rustup toolchain install 1.92.0 --profile minimal
cargo +1.92.0 check --locked --features ort/load-dynamic
alpine:
needs: policy
if: needs.policy.outputs.scope == 'full'
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.policy.outputs.alpine) }}
runs-on: ${{ matrix.os }}
timeout-minutes: 40
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Validate Alpine source and package consumers
env:
TARGET: ${{ matrix.target }}
run: |
docker build -f ci/containers/alpine.Dockerfile -t ortex-alpine .
docker run --name ortex-alpine -e "TARGET=$TARGET" ortex-alpine
docker cp ortex-alpine:/app/dist ./dist
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: nif-${{ matrix.target }}
path: dist/*-${{ matrix.target }}.tar.gz
retention-days: 14
if-no-files-found: error
validated:
if: always()
needs: [policy, hygiene, source, msrv, alpine]
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Require every selected validation job
env:
RESULTS: ${{ toJSON(needs) }}
run: |
python3 - <<'PY'
import json, os
jobs = json.loads(os.environ['RESULTS'])
scope = jobs['policy']['outputs'].get('scope')
for name, job in jobs.items():
allowed = {'success', 'skipped'} if name == 'alpine' and scope == 'pr' else {'success'}
if job['result'] not in allowed:
raise SystemExit(f"{name}: {job['result']}")
PY
- name: Record full-validation marker
if: needs.policy.outputs.scope == 'full' && github.ref == 'refs/heads/main'
run: echo validated > validation.txt
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
if: needs.policy.outputs.scope == 'full' && github.ref == 'refs/heads/main'
with:
name: compatibility-validated
path: validation.txt
retention-days: 14
39 changes: 0 additions & 39 deletions .github/workflows/ci.yml

This file was deleted.

35 changes: 35 additions & 0 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Nightly compatibility
on:
schedule:
- cron: '23 8 * * *'
workflow_dispatch:
permissions:
contents: read
actions: read
concurrency:
group: nightly-main
cancel-in-progress: false
jobs:
changed:
runs-on: ubuntu-24.04
timeout-minutes: 5
outputs:
run: ${{ steps.changed.outputs.run }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: '3.14.10'
- id: changed
env:
GITHUB_TOKEN: ${{ github.token }}
run: echo "run=$(python scripts/ci.py changed "$GITHUB_SHA")" >> "$GITHUB_OUTPUT"
full:
needs: changed
if: needs.changed.outputs.run == 'true' || github.event_name == 'workflow_dispatch'
# actionlint 1.7.12 does not yet parse GitHub's $/ reusable-workflow syntax.
uses: ./.github/workflows/checks.yml # zizmor: ignore[self-repository]
with:
scope: full
21 changes: 19 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
.DEFAULT_GOAL := help
PYTHON ?= python3
export PATH := $(CURDIR)/.venv/bin:$(CURDIR)/.venv/Scripts:$(PATH)
VENV_PYTHON = $(if $(filter Windows_NT,$(OS)),.venv/Scripts/python.exe,.venv/bin/python)
export PATH := $(CURDIR)/.venv/bin:$(CURDIR)/.venv/Scripts:$(CURDIR)/.cache/audit/bin:$(PATH)
export MIX_ENV := test
export ORT_DYLIB_PATH ?= $(shell $(PYTHON) scripts/install_runtime.py path 2>/dev/null)

.PHONY: help setup deps doctor test docs hooks fmt lint check
.PHONY: test.system test.package test.models test.tooling coverage bench fixtures package
.PHONY: test.alpine
.PHONY: setup.audit audit setup.rust

help: ## Show development commands
@awk 'BEGIN {FS = ":.*## "} /^[a-zA-Z0-9_.-]+:.*## / {printf " %-22s %s\n", $$1, $$2}' $(MAKEFILE_LIST)

setup: ## Fetch Mix dependencies and the development runtime
$(MAKE) setup.rust
mix local.hex --force
mix local.rebar --force
$(MAKE) deps
$(PYTHON) scripts/install_runtime.py install
$(PYTHON) -m venv .venv
.venv/bin/python -m pip install -r scripts/requirements.txt
$(VENV_PYTHON) -m pip install -r scripts/requirements.txt

deps: ## Fetch the locked test and documentation dependencies
mix deps.get --check-locked
Expand Down Expand Up @@ -71,3 +75,16 @@ fixtures: ## Regenerate model fixtures (requires the separate exporter environme

package: ## Assemble the local Hex archive
$(PYTHON) scripts/package.py build

test.alpine: ## Run the same suites in the pinned Alpine environment
docker build -f ci/containers/alpine.Dockerfile -t ortex-foundation-alpine .
docker run --rm ortex-foundation-alpine

setup.audit: ## Install the pinned advisory checker into the local cache
cargo install cargo-audit --version 0.22.2 --locked --root .cache/audit

setup.rust: ## Install the pinned Rust compiler, formatter, and Clippy
$(PYTHON) scripts/toolchain.py

audit: ## Report Rust advisories and retired Hex dependencies
$(PYTHON) scripts/audit.py
Loading
Loading