Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
42 changes: 37 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,20 @@ on:
pull_request:
branches: [main]

permissions:
contents: read

jobs:
unit-tests:
name: Unit Tests
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11", "3.12", "3.13"]
python-version: ["3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7

- uses: actions/setup-python@v5
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}

Expand All @@ -28,15 +31,44 @@ jobs:
- name: Run unit tests
run: python -m pytest tests/ --ignore=tests/test_integration.py -v

package:
name: Package
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7

- uses: actions/setup-python@v6
with:
python-version: "3.11"

- name: Install build tools
run: python -m pip install --upgrade build twine

- name: Check Python syntax
run: python -m compileall -q insforge tests

- name: Build distributions
run: python -m build

- name: Check distribution metadata
run: python -m twine check dist/*

- name: Smoke test wheel
run: |
python -m venv /tmp/insforge-wheel-test
/tmp/insforge-wheel-test/bin/python -m pip install dist/*.whl
cd /tmp
/tmp/insforge-wheel-test/bin/python -c 'import insforge; from importlib.metadata import version; print(version("insforge"))'

integration-tests:
name: Integration Tests
runs-on: ubuntu-latest
needs: unit-tests
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7

- uses: actions/setup-python@v5
- uses: actions/setup-python@v6
with:
python-version: "3.13"

Expand Down
79 changes: 79 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: Publish to PyPI

on:
push:
tags:
- "v*"

permissions:
contents: read

concurrency:
group: pypi-${{ github.ref }}
cancel-in-progress: false

jobs:
build:
name: Build distributions
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7

- uses: actions/setup-python@v6
with:
python-version: "3.11"

- name: Validate tag matches package version
env:
RELEASE_TAG: ${{ github.ref_name }}
run: |
package_version="$(python -c 'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])')"
if [ "$RELEASE_TAG" != "v$package_version" ]; then
echo "Tag $RELEASE_TAG does not match package version $package_version."
exit 1
fi

- name: Install test and build tools
run: |
python -m pip install --upgrade -e .
python -m pip install --upgrade pytest pytest-asyncio build twine

- name: Run unit tests
run: python -m pytest tests/ --ignore=tests/test_integration.py -v

- name: Build distributions
run: python -m build

- name: Check distribution metadata
run: python -m twine check dist/*

- name: Smoke test wheel
run: |
python -m venv /tmp/insforge-wheel-test
/tmp/insforge-wheel-test/bin/python -m pip install dist/*.whl
cd /tmp
/tmp/insforge-wheel-test/bin/python -c 'import insforge; from importlib.metadata import version; print(version("insforge"))'

- name: Upload distributions
uses: actions/upload-artifact@v7
with:
name: python-package-distributions
path: dist/
if-no-files-found: error
retention-days: 1

publish:
name: Publish distributions
needs: build
runs-on: ubuntu-latest
permissions:
id-token: write
steps:
- name: Download distributions
uses: actions/download-artifact@v8
with:
name: python-package-distributions
path: dist/

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@v1.14.0
16 changes: 9 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,18 +257,20 @@ python -m build

This produces `dist/insforge-<version>.tar.gz` and `dist/insforge-<version>-py3-none-any.whl`.

### Publish to PyPI
### Release to PyPI

```bash
pip install twine
Publishing uses PyPI Trusted Publishing through `.github/workflows/publish.yml`; no PyPI API token is stored in GitHub. The workflow publishes both the wheel and source distribution and produces digital attestations.

# Test PyPI (recommended first)
twine upload --repository testpypi dist/*
1. Update `project.version` in `pyproject.toml` and merge the change to `main` after CI passes.
2. Create and push an annotated tag that exactly matches the package version with a `v` prefix:

# Production PyPI
twine upload dist/*
```bash
git tag -a vX.Y.Z -m "vX.Y.Z"
git push origin vX.Y.Z
```

The tag triggers a build, metadata validation, and publication to PyPI. PEP 440 prerelease versions are supported as long as the tag exactly matches the version in `pyproject.toml`.

## License

See [LICENSE](LICENSE) for details.
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ dependencies = [
"pydantic>=2.0",
]

[project.urls]
Source = "https://github.com/InsForge/insforge-python"
Issues = "https://github.com/InsForge/insforge-python/issues"

[tool.setuptools]
packages = [
"insforge",
Expand Down
Loading