feature:release
Release a feature. Auto-infer its contract, bump version, tag, publish to GitHub and PyPI, and create a versioned cache snapshot.
Table of contents
Usage
splent feature:release <feature_name> [<version>] [--attach] [--skip-checks]
[--no-github] [--no-pypi] [--allow-unfinished]
| Argument / Option | Description |
|---|---|
<feature_name> |
Feature to release (splent_feature_auth or splent-io/splent_feature_auth). |
<version> |
Optional. Version to release (e.g. v1.2.7). If omitted, the semver wizard runs. |
--attach |
After release, attach the new version to the active product. |
--skip-checks |
Bypass the pre-release gate (lint + tests), for emergencies only. It does not bypass the channel gate. |
--no-github |
Publish to PyPI only. Nothing at all is pushed to GitHub for this version, so the commit and the tag stay on this machine and no cache snapshot is created. |
--no-pypi |
Publish to GitHub only. The feature will not exist on PyPI for this version, and a production build cannot install it. |
--allow-unfinished |
Release even though the previous version never finished publishing. The older version stays broken. |
Releasing a feature needs no account and no token beyond your own GitHub and PyPI credentials. There is nothing to log in to, and the git tag is the publication.
The release refuses to start unless every channel it publishes to would accept it right now, so a version number is never burned on a credential that was going to fail.
Examples
With the semver wizard (recommended)
Omit the version and the wizard fetches the current tag from GitHub, shows the three semver options, and asks you to choose.
splent feature:release splent_feature_auth
Fetching current version from GitHub...
Current version: v1.2.6
Bump type:
[1] patch v1.2.7 bug fixes, no new features
[2] minor v1.3.0 new features, backward compatible
[3] major v2.0.0 breaking changes
[4] cancel
Choice: 1
Will release as v1.2.7
Proceed? [y/N]: y
Releasing splent_io/splent_feature_auth v1.2.7
Release gate (channels)
github ready, splent-io/splent_feature_auth accepts push, tag and release as drorganvidez
pypi ready, credentials accepted, splent_feature_auth exists so this is a new version
contract updating from source code...
contract written to pyproject.toml
version 1.2.7 written to pyproject.toml
commit changes committed
pypi building package...
pypi upload complete
tag v1.2.7 created
tag v1.2.7 pushed to origin
github release created: https://github.com/...
snapshot splent_feature_auth@v1.2.7 (read-only)
splent_io/splent_feature_auth v1.2.7 released.
With an explicit version
splent feature:release splent_feature_auth v1.2.7
Release and attach to the active product
splent feature:release splent_feature_auth --attach
Description
Performs a full release pipeline.
- Validates environment credentials.
- Channel gate, pass one. Proves every enabled channel would accept this exact version, before anything is spent on tests.
- Pre-release gate. Runs
rufflint +feature:teston the feature. Aborts with no changes if either fails. Skip with--skip-checks. - Channel gate, pass two. The binding one, so the verdict acted on is seconds old rather than minutes.
- Updates
[project].versionto<version>. - Infers the feature contract from source code (see below) and writes it to
[tool.splent.contract]. - Stages and commits, locally.
- Cleans build artifacts, builds, and uploads the package to PyPI.
- Pushes
main, creates and pushes the Git tag, creates the GitHub Release. - Compiles frontend assets (delegates to
feature:compile) and creates a versioned snapshot in.splent_cache(read-only). - Asks whether to attach the released version to the active product (defaults to yes). Use
--attachto skip the prompt and attach automatically.
PyPI is published before anything is pushed, because a PyPI version can never be replaced or removed while an unpushed tag costs nothing. If step 9 fails after step 8 succeeded, the run says the channels have diverged and prints the release:resume command that finishes the job without bumping the version.
The cache snapshot is a clone of the tag from GitHub, so with --no-github there is no tag on the remote and no snapshot is created. The command says so rather than failing.
Automatic contract inference
Before any versioning step, feature:release delegates to feature:contract --write to scan the feature’s source code and rewrite [tool.splent.contract] in pyproject.toml. Both commands use the same update_contract() function, ensuring consistent inference whether done during development or at release time.
[tool.splent.contract]
description = "Authentication feature" # ← preserved if already set
[tool.splent.contract.provides]
routes = ["/auth/login", "/auth/logout", "/auth/register"]
blueprints = ["auth_bp"]
models = ["User"]
commands = []
hooks = ["layout.anonymous_sidebar", "layout.authenticated_sidebar"]
services = ["AuthService"]
docker = []
signals = ["user_registered", "user_logged_in"]
translations = ["en", "es"]
[tool.splent.contract.requires]
features = []
env_vars = ["SECRET_KEY", "MAIL_SERVER"]
signals = ["profile_updated"]
[tool.splent.contract.extensible]
hooks = true
signals = true
What is scanned.
| Field | Source file | What is detected |
|---|---|---|
provides.routes |
routes.py |
@<bp>.route(...) decorator paths |
provides.blueprints |
__init__.py |
BaseBlueprint / Blueprint variable names |
provides.models |
models.py |
class <Name>(db.Model) definitions |
provides.commands |
commands.py |
@click.command("name") decorators in commands.py |
provides.hooks |
hooks.py |
register_template_hook("slot", func) slot names |
provides.services |
services.py |
class <Name>(BaseService) definitions |
provides.docker |
feature root | docker-compose*.yml / docker-compose*.yaml files |
provides.signals |
signals.py |
define_signal() calls in signals.py |
provides.translations |
translations/ |
Locale directories in translations/ |
requires.features |
all .py files |
Imports of other splent_feature_* packages |
requires.env_vars |
all .py files |
os.getenv(...) and os.environ[...] calls |
requires.signals |
signals.py |
connect_signal() calls in signals.py |
The developer’s description field is preserved across releases. Everything else is regenerated from source.
Run splent feature:release after every meaningful change to keep the contract accurate. Other products and product:validate rely on this data.
Requirements
Environment variables.
| Variable | Purpose |
|---|---|
SPLENT_APP |
Active product (required for --attach) |
TWINE_USERNAME / PYPI_USERNAME |
PyPI authentication |
TWINE_PASSWORD / PYPI_PASSWORD |
PyPI authentication |
GITHUB_TOKEN |
Required for creating GitHub Releases and for the semver wizard to fetch the current version without rate limits |
Result
After a successful release.
- The feature contract in
pyproject.tomlis up to date. - A Git tag is pushed.
- A GitHub Release is created.
- The package is published to PyPI.
- A versioned snapshot exists at this path.
<workspace>/.splent_cache/features/<namespace>/<feature_name>@<version>/
If --attach is used, the feature version is also linked to the active product and recorded in splent.manifest.json with state declared.
Notes
- The feature must be in editable (non-versioned) state at workspace root. Use
feature:unlockfirst to convert a versioned snapshot. - The semver wizard fetches the latest GitHub tag to compute the next version. If no tags exist yet, it starts from
v0.0.0and suggestsv0.0.1/v0.1.0/v1.0.0. - The wizard offers patch, minor, major, and cancel. Choosing cancel aborts immediately. The wizard also ends with a
Proceed?confirmation before doing anything irreversible. - Passing an explicit
<version>skips the wizard entirely, useful in CI or when you know exactly what to release. - Build artifacts (
__pycache__,dist/,build/) are cleaned automatically before the PyPI build to prevent stale files or permission issues from causing build failures.
See also
feature:contract. Infer or update the contract independently (same logic used here)feature:attach. Pin a released version to a productproduct:validate. Compare feature contracts before releasingfeature:status. Verify state after attachingexport:puml. Generate diagrams from contracts- Feature contract. Contract format reference