Plesty Documentation

Publishing a Release

How to tag a release, trigger the CI build-and-publish pipeline, and verify the package on PyPI.

Package naming

PLESTY packages follow a fixed naming convention:

Convention Example
Distribution name (PyPI, pyproject.toml [project] name) plesty-<module> plesty-power-meter
Import package (namespace) plesty.<module> plesty.power_meter

The distribution name is what users type in pip install / uv add; the import package lives inside the shared plesty namespace. plesty init scaffolds both correctly — verify they still match before the first release, because the distribution name on PyPI cannot be changed later without publishing under a new name.

One-time setup: PyPI credentials

The release job (Gate 14) uploads with uv publish --token "$PYPI_TOKEN". Before the first release of a project, PYPI_TOKEN must be configured — once per project:

  1. Create the token on PyPI: pypi.org → Account settings → API tokensAdd API token. After the first release exists, replace it with a token scoped to the single project instead of the whole account.
  2. Add it as a CI/CD variable: in the GitLab project, Settings → CI/CD → Variables → add PYPI_TOKEN, flagged Masked and Protected.
  3. Protect the release tags: Settings → Repository → Protected tags → protect the pattern v*.

Step 3 is the one that is easy to miss: a protected variable is only exposed to pipelines running on protected branches or tags. If v* tags are not protected, every gate passes but the release job fails with PYPI_TOKEN is empty. If you see that error on an otherwise green pipeline, check the protected-tags setting first.

For a dry run against TestPyPI (see below), no CI variable is needed — the upload runs locally with a TestPyPI token.

Pre-flight checklist

Before tagging, verify everything is in order:

# 1. Run the full quantum check
uv run plesty check --standard quantum

# 2. Review unreleased commits
git log $(git describe --tags --abbrev=0 2>/dev/null || echo "")..HEAD --oneline

# 3. Confirm CHANGELOG is updated
cat CHANGELOG.md | head -20

# 4. Confirm the current branch is clean
git status

All gates must pass. The CHANGELOG must have an entry for this release. Do not tag until the check passes — CI Gate 14 runs the same check in a clean environment and will reject the build if it fails.

Determine the version bump

Commits since last tag contain Bump
Any feat: or feat!: (no breaking change) minor: v0.2.xv0.3.0
Only fix:, chore:, docs:, refactor: patch: v0.2.1v0.2.2
Any feat!: or BREAKING CHANGE: in footer major: v0.2.xv1.0.0

Tag and push

git tag v0.3.0
git push origin v0.3.0

Do not push the tag to a branch — push the tag directly. GitLab detects the v* pattern and triggers Gate 14.

What happens in CI after the tag push

  1. check stage: plesty check --standard quantum runs in a clean environment
  2. security stage: secret scan
  3. deploy stage: Sphinx docs build → push to docs-build branch
  4. release stage: uv builduv publish --token "$PYPI_TOKEN" to PyPI

The package is live on PyPI within a few minutes of the pipeline completing. It will be installable as:

pip install plesty-power-meter==0.3.0
# or
uv add plesty-power-meter==0.3.0

Monitoring the pipeline

glab ci list -R plesty/hub/devices/<vendor>/<project> --ref v0.3.0

Or watch on the GitLab web UI under CI/CD → Pipelines.

Dry run: the TestPyPI channel

Before a first real release, verify the packaging end-to-end on TestPyPI. Build locally and upload with a TestPyPI token:

uv build
uv run twine upload --repository testpypi dist/*

Then install from the test channel in a clean environment (--extra-index-url lets dependencies resolve from real PyPI):

pip install --index-url https://test.pypi.org/simple/ \
            --extra-index-url https://pypi.org/simple/ \
            <your-package>

Runnable end-to-end example

The demo experiment (plesty-demo-experiment) is published on the TestPyPI channel and runs a mock line scan with no hardware attached — it is the reference for what a finished, published module looks like:

pip install --index-url https://test.pypi.org/simple/ \
            --extra-index-url https://pypi.org/simple/ \
            plesty-demo-experiment
python -m plesty.demo_experiment --points 5

After the release

  1. Update docs/index.md to reference the new version (if it mentions a version number)
  2. Start the next CHANGELOG section:
## Unreleased

(no changes yet)
  1. Notify the team if this release has API changes that downstream experiments must accommodate