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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
15 changes: 7 additions & 8 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ jobs:
with:
python-version: '3.12'
cache: pip
cache-dependency-path: requirements-docs.txt
cache-dependency-path: |
requirements-docs.txt
requirements-codegen.txt
- uses: ./.github/actions/setup-haskell
with:
ghc-version: '9.10.3'
Expand All @@ -36,14 +38,11 @@ jobs:
run: |
python -m pip install -r requirements-docs.txt
python tools/build_docs.py
- name: Verify Python documentation examples against the released package
- name: Verify Python examples against this source revision
run: |
python - <<'PY'
import pathlib, subprocess, sys, tomllib
version = tomllib.loads(pathlib.Path('pyproject.toml').read_text())['project']['version']
subprocess.run([sys.executable, '-m', 'pip', 'install', f'hmath-python[numpy,cffi]=={version}'], check=True)
PY
python tools/check_docs_examples.py
python -m pip install numpy cffi
python meson-build.py . build-docs/libhmath.so --builddir build-docs/cabal --offline
HMATH_LIBRARY="$PWD/build-docs/libhmath.so" PYTHONPATH="$PWD/bindings/python" python tools/check_docs_examples.py
- uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3
with:
path: site
Expand Down
97 changes: 97 additions & 0 deletions .github/workflows/prepare-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# SPDX-License-Identifier: MPL-2.0
name: Prepare HMath release

on:
workflow_dispatch:
workflow_call:
outputs:
version:
description: Version checked against all language packages
value: ${{ jobs.preflight.outputs.version }}

permissions:
contents: read

jobs:
preflight:
runs-on: ubuntu-24.04
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
with:
python-version: '3.12'
- uses: ./.github/actions/setup-haskell
with:
ghc-version: '9.10.3'
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: build-docs/cabal
key: docs-haddock-${{ hashFiles('hmath.cabal', 'cabal.project', 'src/**', 'cbits/**') }}
restore-keys: docs-haddock-
- name: Check every public API before preparing a complete release
run: |
python -m pip install -r requirements-docs.txt
python tools/generate_numeric_bindings.py --check
python tools/generate_matrix_bindings.py --check
python tools/build_docs.py
interface=$(python - <<'PY'
import json, pathlib
plan = json.loads(pathlib.Path('build-docs/cabal/cache/plan.json').read_text())
library = next(u for u in plan['install-plan'] if u.get('pkg-name') == 'hmath' and u.get('component-name') == 'lib')
print(pathlib.Path(library['dist-dir']) / 'doc/html/hmath/hmath.haddock')
PY
)
python tools/check_binding_coverage.py --interface "$interface" --require-complete
- name: Read the single project version
id: version
run: echo "version=$(python tools/release_version.py)" >> "$GITHUB_OUTPUT"
validate:
needs: preflight
uses: ./.github/workflows/validate.yml
with:
full-matrix: true
distributions:
needs: preflight
uses: ./.github/workflows/python-wheels.yml
haskell-source:
needs: distributions
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: ./.github/actions/setup-haskell
with:
ghc-version: '9.10.3'
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
with:
name: native-distributions
path: source-artifacts
- name: Build the actual Cabal source archive
run: |
version=$(python tools/release_version.py)
mkdir "$RUNNER_TEMP/hmath-source"
tar -xzf "source-artifacts/hmath-$version.tar.gz" -C "$RUNNER_TEMP/hmath-source"
cd "$RUNNER_TEMP/hmath-source/hmath-$version"
cabal check
cabal build lib:hmath flib:hmath --offline -O0
ready:
needs: [preflight, validate, distributions, haskell-source]
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
with:
python-version: '3.12'
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
with:
pattern: '*-distributions'
path: candidate
merge-multiple: true
- name: Record checksums and source identity
run: python tools/release_manifest.py candidate --commit "$GITHUB_SHA" --run-id "$GITHUB_RUN_ID"
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: release-candidate
path: candidate/*
if-no-files-found: error
117 changes: 73 additions & 44 deletions .github/workflows/publish-python.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: MPL-2.0
name: Publish Python and GitHub Release
name: Publish HMath release

on:
workflow_dispatch:
Expand All @@ -9,73 +9,102 @@ on:
type: choice
options: [testpypi, pypi]
default: testpypi
candidate_run_id:
description: Prepared run ID (blank resumes the staged candidate or selects the latest successful preparation for this commit)
type: string
required: false

permissions:
contents: read
actions: read

concurrency:
group: publish-python-${{ inputs.index }}
group: publish-hmath-${{ inputs.index }}
cancel-in-progress: false

jobs:
build:
select:
if: github.repository == 'wavefnd/hmath' && github.ref == 'refs/heads/master'
uses: ./.github/workflows/python-wheels.yml
runs-on: ubuntu-24.04
outputs:
run_id: ${{ steps.candidate.outputs.candidate_run_id }}
version: ${{ steps.candidate.outputs.version }}
source_sha: ${{ steps.candidate.outputs.candidate_sha }}
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- name: Select an existing verified candidate without rebuilding it
id: candidate
env:
GH_TOKEN: ${{ github.token }}
CANDIDATE_RUN_ID: ${{ inputs.candidate_run_id }}
run: python tools/select_release_candidate.py --repository "$GITHUB_REPOSITORY" --commit "$GITHUB_SHA" --run-id "$CANDIDATE_RUN_ID"

publish:
needs: build
needs: select
runs-on: ubuntu-24.04
environment:
name: ${{ inputs.index }}
permissions:
id-token: write
contents: write
actions: read
steps:
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- name: Download the selected immutable candidate
env:
GH_TOKEN: ${{ github.token }}
CANDIDATE_RUN_ID: ${{ needs.select.outputs.run_id }}
run: gh run download "$CANDIDATE_RUN_ID" --repo "$GITHUB_REPOSITORY" --name release-candidate --dir candidate
- name: Verify all artifacts and source identity
env:
SOURCE_SHA: ${{ needs.select.outputs.source_sha }}
VERSION: ${{ needs.select.outputs.version }}
RUN_ID: ${{ needs.select.outputs.run_id }}
run: python tools/verify_release_candidate.py candidate --commit "$SOURCE_SHA" --version "$VERSION" --run-id "$RUN_ID"
- name: Verify existing package hashes before external writes
id: remote
env:
SOURCE_SHA: ${{ needs.select.outputs.source_sha }}
run: python tools/check_release_remote.py --python candidate --native candidate --commit "$SOURCE_SHA" --index '${{ inputs.index }}'
- name: Require Hackage configuration for a new Haskell upload
if: inputs.index == 'pypi' && steps.remote.outputs.haskell_complete != 'true'
env:
HACKAGE_TOKEN: ${{ secrets.HACKAGE_TOKEN }}
run: test -n "$HACKAGE_TOKEN"
- name: Verify and stage all GitHub assets before package publication
if: inputs.index == 'pypi'
env:
GH_TOKEN: ${{ github.token }}
SOURCE_SHA: ${{ needs.select.outputs.source_sha }}
run: python tools/publish_github_release.py candidate --repository "$GITHUB_REPOSITORY" --commit "$SOURCE_SHA" --stage-only
- uses: ./.github/actions/setup-haskell
if: inputs.index == 'pypi' && steps.remote.outputs.haskell_complete != 'true'
with:
name: python-distributions
path: dist/
ghc-version: '9.10.3'
- name: Publish the verified Cabal source package
if: inputs.index == 'pypi' && steps.remote.outputs.haskell_complete != 'true'
env:
HACKAGE_TOKEN: ${{ secrets.HACKAGE_TOKEN }}
VERSION: ${{ needs.select.outputs.version }}
run: cabal upload --publish --token="$HACKAGE_TOKEN" "candidate/hmath-$VERSION.tar.gz"
- name: Stage Python-only upload files
run: |
mkdir dist
cp candidate/*.whl candidate/hmath_python-*.tar.gz dist/
- name: Publish to TestPyPI
if: inputs.index == 'testpypi'
if: inputs.index == 'testpypi' && steps.remote.outputs.python_complete != 'true'
uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # release/v1
with:
repository-url: https://test.pypi.org/legacy/
skip-existing: true
- name: Publish to PyPI
if: inputs.index == 'pypi'
if: inputs.index == 'pypi' && steps.remote.outputs.python_complete != 'true'
uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # release/v1

github-release:
if: inputs.index == 'pypi'
needs: [build, publish]
runs-on: ubuntu-24.04
permissions:
contents: write
steps:
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
with:
name: python-distributions
path: dist/
- name: Create the versioned GitHub release
skip-existing: true
- name: Publish the staged GitHub release
if: inputs.index == 'pypi'
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
RELEASE_VERSION: ${{ needs.build.outputs.version }}
RELEASE_SHA: ${{ github.sha }}
run: |
tag="v$RELEASE_VERSION"
error_log="$RUNNER_TEMP/release-tag-error.log"
if ! existing="$(gh api "repos/$GH_REPO/commits/$tag" --jq .sha 2>"$error_log")"; then
if ! grep -Eq '\(HTTP (404|422)\)' "$error_log"; then
cat "$error_log" >&2
exit 1
fi
existing=""
fi
if [ -n "$existing" ] && [ "$existing" != "$RELEASE_SHA" ]; then
echo "Tag $tag points to another commit; refusing to publish mismatched artifacts."
exit 1
fi
gh release create "$tag" dist/* \
--target "$RELEASE_SHA" \
--title "HMath $RELEASE_VERSION" \
--generate-notes \
--latest
SOURCE_SHA: ${{ needs.select.outputs.source_sha }}
run: python tools/publish_github_release.py candidate --repository "$GITHUB_REPOSITORY" --commit "$SOURCE_SHA"
34 changes: 32 additions & 2 deletions .github/workflows/python-wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,39 @@ jobs:
- name: Build self-contained manylinux wheel and source distribution
run: |
docker run --rm --volume "$PWD:/io" \
--env SOURCE_DATE_EPOCH="$(git show -s --format=%ct HEAD)" \
quay.io/pypa/manylinux_2_28_x86_64@sha256:e0adf18521ad35192df733a6c62d35df7801957d24e0470238aacecfab2188a3 \
bash /io/tools/build_python_wheel.sh
python -m pip install twine
python -m twine check --strict dist/*
python -m twine check --strict dist/*.whl dist/hmath_python-*.tar.gz
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: python-distributions
path: dist/*
path: |
dist/*.whl
dist/hmath_python-*.tar.gz
if-no-files-found: error
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: native-distributions
path: dist/native/*
if-no-files-found: error

c-sdk:
needs: build
runs-on: ubuntu-24.04
container: python:3.12-slim-bookworm
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
with:
name: native-distributions
path: /tmp/hmath-native
- name: Verify the relocated SDK without GHC
run: |
apt-get update
apt-get install -y --no-install-recommends build-essential pkg-config cmake
python tools/check_c_sdk.py /tmp/hmath-native/hmath-*-linux-x86_64.tar.gz

test:
needs: build
Expand All @@ -70,4 +94,10 @@ jobs:
python "$GITHUB_WORKSPACE/tools/check_python_wheel.py"
python -m pip install numpy cffi
python "$GITHUB_WORKSPACE/tools/check_python_wheel.py" "$GITHUB_WORKSPACE/bindings/python/test_bindings.py"
python "$GITHUB_WORKSPACE/tools/check_python_wheel.py" "$GITHUB_WORKSPACE/test/native/expanded_bindings.py"
python "$GITHUB_WORKSPACE/tools/check_python_wheel.py" "$GITHUB_WORKSPACE/test/native/autodiff_bindings.py"
for contract in value polynomial optimization units expression linear stochastic numerical spectral foundation tensor; do
python "$GITHUB_WORKSPACE/tools/check_python_wheel.py" "$GITHUB_WORKSPACE/test/native/${contract}_bindings.py"
done
python "$GITHUB_WORKSPACE/tools/check_python_wheel.py" "$GITHUB_WORKSPACE/test/native/callback_errors.py"
python "$GITHUB_WORKSPACE/tools/check_docs_examples.py"
4 changes: 3 additions & 1 deletion .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ jobs:
${{ steps.haskell.outputs.cabal-store }}
dist-newstyle
build-ci/cabal
build-ci/numeric-oracle
build-interchange/cabal
key: cabal-${{ runner.os }}-${{ matrix.ghc }}-${{ matrix.buildtype }}-${{ hashFiles('hmath.cabal', 'cabal.project', 'src/**', 'cbits/**', 'test/**', 'bench/**') }}
restore-keys: cabal-${{ runner.os }}-${{ matrix.ghc }}-${{ matrix.buildtype }}-
Expand All @@ -58,7 +59,7 @@ jobs:
run: |
sudo apt-get update
sudo apt-get install -y liblapacke-dev libopenblas-dev zlib1g-dev cmake ninja-build clang
python -m pip install meson==1.8.5 numpy cffi
python -m pip install -r requirements-codegen.txt meson==1.8.5 numpy cffi
- name: Wave compiler
if: matrix.primary
env:
Expand Down Expand Up @@ -114,6 +115,7 @@ jobs:
${{ steps.haskell.outputs.cabal-store }}
dist-newstyle
build-ci/cabal
build-ci/numeric-oracle
build-interchange/cabal
key: cabal-extended-${{ runner.os }}-9.10.3-${{ hashFiles('hmath.cabal', 'cabal.project', 'src/**', 'cbits/**', 'test/**', 'bench/**') }}
restore-keys: |
Expand Down
7 changes: 4 additions & 3 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
include LICENSE README.md CHANGELOG.md ROADMAP.md hmath.cabal cabal.project meson-build.py
include meson.build meson_options.txt mkdocs.yml requirements-docs.txt fourmolu.yaml .clang-format
include meson.build meson_options.txt mkdocs.yml requirements-docs.txt requirements-codegen.txt fourmolu.yaml .clang-format
recursive-include src *.hs
recursive-include cbits *.c *.h
recursive-include include *.h
recursive-include bindings/python/_hmath_native/licenses *
recursive-include bindings/python *.py LICENSE
recursive-include bindings/wave *.wave
recursive-include docs *.md
recursive-include docs *.md *.css *.js
recursive-include tools *.py *.sh
recursive-include test *.hs *.c *.py *.txt
recursive-include test *.hs *.c *.cpp *.py *.txt
recursive-include examples *.hs *.c *.py
recursive-include bench *.hs *.c
recursive-include meson *.in
recursive-include .github/workflows *.yml
recursive-include bindings/schema *.json *.txt
Loading
Loading