# Releasing

Releases go to PyPI from GitHub Actions with [trusted publishing](https://docs.pypi.org/trusted-publishers/):
the workflow proves its identity to PyPI with a short-lived OpenID Connect token, so no API
token is stored anywhere. Each upload also carries a PEP 740 attestation tying the artifact to
the workflow run that built it.

## One-time setup on PyPI

Done once by the project owner, before the first tag.

1. Sign in at [pypi.org](https://pypi.org) and open **Your account → Publishing**.
2. Under **Add a new pending publisher**, fill in:

   | field | value |
   |---|---|
   | PyPI project name | `xpsflow` |
   | Owner | `KarthikSubramanian07` |
   | Repository name | `XPS-Flow` |
   | Workflow name | `release.yml` |
   | Environment name | `pypi` |

3. In the GitHub repository, open **Settings → Environments → New environment**, name it
   `pypi`, and (recommended) add yourself as a required reviewer. Every publish then waits for
   one click of approval.

The pending publisher turns into the real project the first time the workflow uploads.

## Cutting a release

1. Set `version` in `pyproject.toml`, update anything user-visible that mentions the
   version, and merge that change to `main` through a pull request.
2. Tag the merge commit and push the tag:

   ```bash
   git switch main && git pull
   git tag -a v0.1.0 -m "xpsflow 0.1.0"
   git push origin v0.1.0
   ```

3. Watch **Actions → Release**. The `build and verify` job rebuilds the sdist and wheel,
   runs `twine check`, installs the wheel into a clean interpreter and runs the full
   pipeline on `examples/demo.vms`. It fails before anything is uploaded if the tag does not
   match the package version.
4. Approve the `pypi` environment if you set a reviewer. The `publish to PyPI` job uploads,
   then `GitHub release` creates the release with generated notes and the artifacts attached.

Afterwards `pip install "xpsflow[web,pdf]"` installs that version, and the is-agentic
"CLI tool" check can resolve the package.

## Checking a release locally

```bash
uv build
uvx twine check --strict dist/*
uv venv -p 3.12 /tmp/smoke && uv pip install -p /tmp/smoke/bin/python "dist/xpsflow-0.1.0-py3-none-any.whl[web]"
/tmp/smoke/bin/xpsflow run examples/demo.vms --out /tmp/smoke-run
```

## Versioning

Semantic versions. Anything that changes a fitted number for the same input (a new
background, a changed default, a corrected sensitivity factor) is at least a minor bump and is
called out in the release notes, because reports record the version that produced them.
