From 694ac7784b304c7293ca8f05a58093dd940677c7 Mon Sep 17 00:00:00 2001 From: Alfred Hall Date: Tue, 7 Jul 2026 16:01:29 +0000 Subject: [PATCH 1/3] ci: PyPI release workflow via Trusted Publishing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Publishes to PyPI on a v* tag using PyPI Trusted Publishing (OIDC) — no API token stored. Version comes from pyproject.toml; the tag is the trigger. Requires a one-time Trusted Publisher set up on PyPI (project isms, unidoc/isms-python, release.yml, environment pypi). --- .github/workflows/release.yml | 37 +++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..6e9d1ab --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,37 @@ +# Publish to PyPI on a version tag, via PyPI Trusted Publishing (OIDC) — no API +# token stored anywhere. The published version is whatever pyproject.toml says; +# the tag (v0.1.0, ...) is just the trigger. Bump pyproject.toml's version and the +# _version.py to match before tagging. +# +# One-time PyPI setup (Trusted Publisher / "pending publisher" for a new project): +# PyPI Project Name: isms +# Owner: unidoc +# Repository name: isms-python +# Workflow name: release.yml +# Environment name: pypi +name: release + +on: + push: + tags: ["v*"] + +permissions: + contents: read + +jobs: + publish: + runs-on: ubuntu-latest + environment: pypi + permissions: + id-token: write # required for PyPI Trusted Publishing (OIDC) + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-python@v5 + with: + python-version: "3.13" + - name: Build sdist + wheel + run: | + python -m pip install --quiet build + python -m build + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 From 3504d0431efccb5764fb92854aa3fe8f745aad81 Mon Sep 17 00:00:00 2001 From: Alfred Hall Date: Tue, 7 Jul 2026 16:11:26 +0000 Subject: [PATCH 2/3] chore: distribution name isms-sdk for PyPI The bare 'isms' name is rejected by PyPI's typosquat / too-similar guard, so the published distribution is isms-sdk. The import stays 'isms' (pip install isms-sdk -> from isms import IsmsClient, same pattern as sentry-sdk / beautifulsoup4). Updates the README install line + an install-vs-import note, and the release workflow's Trusted-Publisher comment (PyPI project name isms-sdk). --- .github/workflows/release.yml | 2 +- README.md | 8 +++++++- pyproject.toml | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6e9d1ab..d370f40 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,7 +4,7 @@ # _version.py to match before tagging. # # One-time PyPI setup (Trusted Publisher / "pending publisher" for a new project): -# PyPI Project Name: isms +# PyPI Project Name: isms-sdk # Owner: unidoc # Repository name: isms-python # Workflow name: release.yml diff --git a/README.md b/README.md index d11a36d..fa44697 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,13 @@ custom dashboards without touching the web UI. ## Install ```sh -pip install isms +pip install isms-sdk +``` + +The distribution is `isms-sdk`; you import it as `isms`: + +```python +from isms import IsmsClient ``` Requires Python 3.10 or later. diff --git a/pyproject.toml b/pyproject.toml index 1365b4f..7954953 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ requires = ["hatchling>=1.24"] build-backend = "hatchling.build" [project] -name = "isms" +name = "isms-sdk" version = "0.1.0" description = "Official Python client for the ISMS platform (isms.sh)" readme = "README.md" From c654d4e898f0ac4f38d0969f9abb147d7260693f Mon Sep 17 00:00:00 2001 From: Alfred Hall Date: Tue, 7 Jul 2026 18:26:13 +0000 Subject: [PATCH 3/3] ci: harden release workflow (tag/version check + test gate) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses Alip's review on PR #3: - Verify the pushed tag matches pyproject.toml's version before build/publish, so a mistagged release can't silently publish the wrong (and unrewritable) version. - Add an in-workflow lint+test job and gate publish on it (needs: test) — tests.yml never runs on tag pushes, so this guarantees lint+tests pass on the exact tagged commit before anything is published. --- .github/workflows/release.yml | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d370f40..a9e0a73 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,7 +1,7 @@ # Publish to PyPI on a version tag, via PyPI Trusted Publishing (OIDC) — no API # token stored anywhere. The published version is whatever pyproject.toml says; -# the tag (v0.1.0, ...) is just the trigger. Bump pyproject.toml's version and the -# _version.py to match before tagging. +# the tag (v0.1.0, ...) is just the trigger — and is checked against it below. +# Bump pyproject.toml's version and _version.py to match before tagging. # # One-time PyPI setup (Trusted Publisher / "pending publisher" for a new project): # PyPI Project Name: isms-sdk @@ -19,7 +19,22 @@ permissions: contents: read jobs: + # tests.yml only runs on push-to-master / PRs, never on tag pushes — so gate the + # release on lint+tests passing on this exact tagged commit. + test: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-python@v5 + with: + python-version: "3.13" + - run: pip install --quiet -e ".[dev]" + - run: ruff check src tests + - run: pytest -q + publish: + needs: test runs-on: ubuntu-latest environment: pypi permissions: @@ -29,6 +44,14 @@ jobs: - uses: actions/setup-python@v5 with: python-version: "3.13" + - name: Verify tag matches project version + run: | + tag_version="${GITHUB_REF_NAME#v}" + project_version="$(python -c 'import tomllib; print(tomllib.load(open("pyproject.toml","rb"))["project"]["version"])')" + if [ "$tag_version" != "$project_version" ]; then + echo "::error::Tag v$tag_version does not match pyproject.toml version $project_version" + exit 1 + fi - name: Build sdist + wheel run: | python -m pip install --quiet build