Skip to content

Contributing to kmhelpers

Dev environment setup

git clone https://github.com/sebllns/kmhelpers
cd kmhelpers
pip install -e ".[dev]"

kmindex and kmtricks must also be available, see Installation.

Project structure

pykmhelpers/
  cli/          # Click commands (one file per command)
  core/         # Low-level building blocks (index, bloom_filter, kmindex_wrapper, ...)
  operations/   # Higher-level operations (builder, fof_validation, ...)
  tests/        # Test suite
  pipeline/     # Pipeline execution engine

Each CLI command in cli/ is a thin layer that delegates to operations/ or core/.

Running tests

pytest

Coverage is reported automatically (configured in pyproject.toml). HTML report is written to htmlcov/.

Code style

Tool Purpose
black Formatting (line length 88)
flake8 Linting
mypy Type checking
black pykmhelpers/
flake8 pykmhelpers/
mypy pykmhelpers/

Branches

Branch Purpose Updated by
main Development trunk, always passing CI; releases are tags vX.Y.Z on it PR
feature/<name>, fix/<name>, doc/<name>, ci/<name>, release/vX.Y.Z Short-lived work, deleted after merge Direct push
docs Hidden docs preview, for docs work in progress Direct push
paper JOSS paper; paper.pdf is committed by CI Direct push
gh-pages Generated by the docs workflow, never edited by hand CI

main is protected: changes land through pull requests. Users install from tags, PyPI or bioconda, not from main.

Workflow

git checkout main
git pull
git checkout -b feature/my-feature
# ... commit ...
git push -u origin feature/my-feature
gh pr create --base main
# after review and green CI:
gh pr merge --squash --delete-branch    # or --merge to keep each commit

Rules:

  • One branch per topic, from an up-to-date main, deleted after merge.
  • To bring new main commits into a pushed branch, use git merge main; rebase only before the first push.
  • git push --force-with-lease only on your own, unshared branch.

Documentation

Docs are versioned with mike on the gh-pages branch, deployed by .github/workflows/docs.yml:

Trigger Deployed as URL
Push to docs Hidden preview /kmhelpers/preview/
Push to main Version main, titled main (<short hash>), overwritten each time /kmhelpers/main/
Tag vX.Y.Z Version X.Y.Z, alias latest (default) /kmhelpers/X.Y.Z/

Content specific to a release or to the development version goes between release-only or dev-only HTML comment markers; @VERSION@ inside a release block is replaced by the version (see scripts/mkdocs_hooks.py, used in docs/getting-started/installation.md). Release builds get DOCS_RELEASE=X.Y.Z from the workflow; to preview one locally:

DOCS_RELEASE=X.Y.Z mkdocs serve

To try docs changes before merging, push them to docs (git push --force origin HEAD:docs) and open the preview.

Manual deploy from any branch or tag (the branch must be pushed):

# Redeploy a release from its tag
gh workflow run docs.yml --ref vX.Y.Z

# Deploy a branch as a given version, without moving "latest"
gh workflow run docs.yml --ref fix/docs-typo -f version=X.Y.Z -f latest=false

# Deploy and remove an old version
gh workflow run docs.yml --ref vX.Y.Z -f delete_version=<old>

# Follow the run
gh run watch $(gh run list --workflow docs.yml --limit 1 --json databaseId --jq '.[0].databaseId')

Without -f version, the version is the package version of the ref (main on main). latest defaults to true. A release version gets the release-only blocks, like a tag build.

Releasing

pykmhelpers/_version.py is the single source of the version. Commands below use VERSION=X.Y.Z.

1. Prepare

git checkout main
git pull
git checkout -b release/v$VERSION
  • Set __version__ = "X.Y.Z" in pykmhelpers/_version.py.
  • Add the ## [X.Y.Z] - YYYY-MM-DD section to CHANGELOG.md. It becomes the GitHub release notes, so it must be written before tagging.
pytest
rm -rf dist && python -m build && twine check dist/*
git commit -am "release: v$VERSION"
git push -u origin release/v$VERSION

2. Merge into main

gh pr create --base main --title "Release v$VERSION" --body "See CHANGELOG.md"
gh pr checks --watch
gh pr merge --merge --delete-branch

3. Tag

git checkout main
git pull
git tag -a v$VERSION -m "kmhelpers v$VERSION" \
    -m "Documentation: https://sebllns.github.io/kmhelpers/$VERSION/
Changelog: https://sebllns.github.io/kmhelpers/$VERSION/changelog/"
git push origin v$VERSION

Or with git create-release (scripts/git-create-release, requires gh), which runs the commands above after checks, then lists the release workflow runs:

git create-release [--view] [--overwrite] [VERSION]

VERSION defaults to pykmhelpers/_version.py; a different one asks for confirmation. Before tagging, it checks that CHANGELOG.md has the ## [VERSION] section, that the tag does not exist, that the working tree is clean and that HEAD is origin/main.

Option Effect
--view Show the release and the workflow runs, no tagging
--overwrite Delete the GitHub release and the tag, then tag again
-h Help (--help is caught by git for aliases)

The alias is defined in the versioned .gitconfig, enable it once per clone:

git config include.path ../.gitconfig

Never move or re-create a pushed tag, except with --overwrite when the release failed before the PyPI upload.

4. Automatic steps

Pushing the tag runs:

  • release.yml: builds the sdist and wheel, creates the GitHub release with the files attached and notes made of .github/release-notes.md (docs links, install and update commands), the CHANGELOG section and the merged PRs, then uploads the files to PyPI (publish job) and installs the published version in a fresh environment to check kmhelpers --version (verify job).
  • docs.yml: deploys the docs as version X.Y.Z with alias latest.
gh run list --limit 4
gh release view v$VERSION    # or: git create-release --view

5. Approve the PyPI upload (browser)

The publish job runs in the pypi environment, which waits for a manual approval:

  1. Open the "Release build" run of the tag in the Actions tab.
  2. Once tests and build are green, check the release: notes, sdist and wheel attached.
  3. Click "Review deployments", select pypi, then "Approve and deploy".
  4. When publish and verify are green, check the version on PyPI and the docs at https://sebllns.github.io/kmhelpers/X.Y.Z/.

A PyPI version cannot be uploaded twice: a broken release is fixed by a new version.

6. Bioconda

After the PyPI upload, the bioconda bot opens a PR in bioconda-recipes updating the version and sha256. Check that runtime dependencies still match pyproject.toml, then approve it.

Patch of an older version

Only when a fix must be released for a version older than main. The tag is created manually, as git create-release only tags origin/main:

git checkout -b maint/vX.Y v$OLD_VERSION
# commit the fix, bump the version, add the CHANGELOG section
git push -u origin maint/vX.Y
git tag -a v$PATCH_VERSION -m "kmhelpers v$PATCH_VERSION"
git push origin v$PATCH_VERSION

Then bring the fix and the CHANGELOG section into main through a PR. This tag gets the latest docs alias; redeploy the newest release afterwards with gh workflow run docs.yml --ref v<newest>.