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
62 changes: 62 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: Release

# Publishes py-sendly to PyPI when a version tag (vX.Y.Z) is pushed.
# Disjoint from ci.yml (push/PR to main + weekly cron): this runs ONLY on tags,
# re-runs the full gate, then publishes. A red SDK can never ship.
on:
push:
tags: ["v*"]

permissions:
contents: read

jobs:
publish:
name: Test, build & publish to PyPI
runs-on: ubuntu-latest
environment: pypi # must match the environment on the PyPI trusted publisher
permissions:
id-token: write # OIDC for PyPI Trusted Publishing (no token stored)
steps:
- uses: actions/checkout@v6.0.3

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

- name: Install build + dev toolchain
run: |
python -m pip install --upgrade pip build
pip install -e ".[dev]"

# Version-consistency gate: the pushed tag must equal both the
# pyproject.toml version and the SDK_VERSION constant (User-Agent header).
- name: Assert tag matches pyproject + SDK_VERSION
run: |
TAG="${GITHUB_REF_NAME#v}"
VER=$(python -c "import tomllib;print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")
SDK=$(python -c "from sendly import SDK_VERSION;print(SDK_VERSION)")
echo "tag=$TAG pyproject=$VER SDK_VERSION=$SDK"
test "$TAG" = "$VER" || { echo "::error::tag $TAG != pyproject $VER"; exit 1; }
test "$TAG" = "$SDK" || { echo "::error::tag $TAG != SDK_VERSION $SDK"; exit 1; }

- name: Ruff lint
run: ruff check .

- name: Ruff format check
run: ruff format --check .

- name: Mypy (strict)
run: mypy src

- name: Contract tests (SDK surface vs vendored OpenAPI)
run: pytest tests/test_contract.py

- name: Pytest
run: pytest

- name: Build sdist + wheel
run: python -m build

- name: Publish to PyPI (Trusted Publishing / OIDC)
uses: pypa/gh-action-pypi-publish@release/v1
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,17 @@ suppression.

## Installation

Not yet published to PyPI. Install from GitHub:
```bash
pip install py-sendly
```

The distribution is published as `py-sendly`; the import name is unchanged:

```python
import sendly
```

Alternatively, install the latest `main` directly from GitHub:

```bash
pip install git+https://github.com/DevinoSolutions/sendly-python.git
Expand Down
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ requires = ["hatchling==1.30.1"]
build-backend = "hatchling.build"

[project]
name = "sendly"
# PyPI distribution name. The plain `sendly` name is owned by an unrelated
# SMS company on PyPI, so we publish as `py-sendly`. The import package is
# unchanged (`import sendly`) — see [tool.hatch.build.targets.wheel] below.
name = "py-sendly"
version = "0.1.0"
description = "Official Sendly Python SDK"
readme = "README.md"
Expand Down
Loading