diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..3347f99 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,60 @@ +name: Publish to PyPI + +on: + push: + tags: + - "v*.*.*" + workflow_dispatch: + +concurrency: + group: publish + cancel-in-progress: false + +jobs: + build: + name: Build sdist and wheel + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install build tooling + run: | + python -m pip install --upgrade pip + python -m pip install build twine + + - name: Build distributions + run: python -m build + + - name: Check metadata + run: twine check dist/* + + - name: Upload dist artifact + uses: actions/upload-artifact@v4 + with: + name: dist + path: dist/ + if-no-files-found: error + + publish: + name: Upload to PyPI (OIDC) + needs: build + runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/project/llm-safe-pl/ + permissions: + id-token: write + steps: + - name: Download dist artifact + uses: actions/download-artifact@v4 + with: + name: dist + path: dist/ + + - name: Publish via trusted publishing + uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b8dd0b5..f9b17d8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -60,6 +60,36 @@ Python 3.10 or newer is required. - Keep PR descriptions short and focused on the *why*, not a diff retelling. - Do not include attribution trailers (`Co-Authored-By`, AI-assistant credits, etc.); if you used tooling to help write code, that is your business, not the project's history. +## Releasing (maintainers only) + +`llm-safe-pl` publishes to PyPI via GitHub Actions using [PyPI trusted publishing](https://docs.pypi.org/trusted-publishers/) (OIDC). No API token is stored in the repository or GitHub secrets. + +Before the first release, configure the trusted publisher once: + +1. On PyPI, go to https://pypi.org/manage/account/publishing/ and add a *pending publisher* for this package (PyPI supports trusted publishing for not-yet-created packages). Values: + - PyPI project name: `llm-safe-pl` + - Owner: `Tatarinho` + - Repository: `llm-safe-pl` + - Workflow filename: `publish.yml` + - Environment name: `pypi` +2. In this repo's GitHub settings, create an environment named `pypi`. Optionally add required reviewers or restrict it to the `main` branch as an extra gate. + +To cut a release: + +1. Land all target changes on `main`. Move items from `[Unreleased]` in `CHANGELOG.md` into a new `[X.Y.Z]` block with today's date. +2. Bump `version` in `pyproject.toml` if the tag will differ from the current value. +3. Commit the changelog and version bump on `main`. +4. Tag the commit and push the tag: + + ```bash + git tag vX.Y.Z + git push origin vX.Y.Z + ``` + +5. The `Publish to PyPI` workflow builds the sdist + wheel, runs `twine check`, and uploads via OIDC. Watch the run under *Actions → Publish to PyPI*. + +Do not commit a PyPI API token. The workflow does not need one. + ## Licensing By submitting a contribution, you agree that it will be distributed under the project's MIT license (see [LICENSE](LICENSE)). No CLA is required.