Release and deploy

Publish splent_feature_notes to PyPI, pin a versioned release, and deploy your product to production.


Table of contents

  1. Prerequisites
  2. Step 1 – Verify credentials
  3. Step 2 – Write the feature contract
  4. Step 3 – Commit and push to GitHub
  5. Step 4 – Release the feature
  6. Step 5 – Pin a version manually (optional)
  7. Step 6 – Resolve the product
  8. Step 7 – Validate the product
  9. Step 8 – Build the production image
  10. Step 9 – Deploy
  11. Step 10 – Shut down production
  12. Step 11 – Back to development
  13. What you learned
  14. Next

Prerequisites

You have completed Tutorial 4 – Testing. You are inside the CLI container with my_first_app selected and splent_feature_notes working with passing tests.

(my_first_app) /workspace$

Part 1 — Release a feature

This part publishes real packages. It requires a GitHub account with a repository for the feature and a PyPI account with an API token. The package published to PyPI is permanent — it cannot be fully deleted. If you are just exploring SPLENT and do not want to publish anything, skip to Part 2 — Deploy to production.


Step 1 – Verify credentials

Before releasing, you need GitHub and PyPI tokens. If you don’t have them yet, run:

splent tokens:setup

This prints step-by-step instructions for obtaining:

  • A GitHub personal access token (for creating releases and pushing tags)
  • A PyPI API token (for publishing packages)

After adding the tokens to your .env file, reload them in your shell:

source .env

Without source .env, the CLI cannot read the tokens you just configured. This is required every time you add or change variables in .env.

Once configured, verify they work:

splent check:github
  ✅ GitHub credentials OK.
splent check:pypi
  ✅ PyPI credentials OK.

Both checks must pass before feature:release will work. If either fails, follow the instructions from splent tokens:setup to fix them.


Step 2 – Write the feature contract

The contract is the machine-readable summary of what your feature provides and requires. It lives in pyproject.toml and is used by other features, the CLI, and the release pipeline.

splent feature:contract splent_feature_notes --write

You will see output like:

  feature:contract -- splent_feature_notes
  ────────────────────────────────────────────────────

  Scanning source code...

  Inferred contract:

  [tool.splent.contract.provides]
  routes     = ["/notes/", "/notes/create", "/notes/<int:id>/edit", "/notes/<int:id>/delete"]
  blueprints = ["notes_bp"]
  models     = ["Notes"]
  commands   = []
  hooks      = ["layout.authenticated_sidebar"]
  services   = ["NotesService"]
  docker     = []

  [tool.splent.contract.requires]
  features   = ["auth"]
  env_vars   = []

  Written to pyproject.toml.

The contract scanner reads your routes, models, hooks, services, and imports automatically. No manual bookkeeping required.

This step is optional — feature:release automatically updates the contract before publishing. Running it manually lets you review the contract before the release.


Step 3 – Commit and push to GitHub

feature:release needs a git repository with a clean working tree. If you have not initialized one yet:

cd /workspace/splent_feature_notes
git init
git add .
git commit -m "Initial release of splent_feature_notes"
git remote add origin git@github.com:splent-io/splent_feature_notes.git
git push -u origin main

Replace the remote URL with your own GitHub repository. The feature needs to be hosted on GitHub for the release pipeline to tag and publish it.


Step 4 – Release the feature

Back in the CLI container:

splent feature:release splent-io/splent_feature_notes

The semver wizard fetches the latest tag from GitHub and offers bump options:

  Fetching current version from GitHub...
  No tags found — this will be the first release.

  Bump type:
    [1] patch  v0.0.1   bug fixes, no new features
    [2] minor  v0.1.0   new features, backward compatible
    [3] major  v1.0.0   breaking changes
    [4] cancel

  Choice: 3

  Will release as v1.0.0
  Proceed? [y/N]: y

After confirmation, the full pipeline runs:

  Releasing splent_io/splent_feature_notes v1.0.0

  contract updating from source code...
  contract written to pyproject.toml
  version  1.0.0 written to pyproject.toml
  commit   changes committed and pushed
  tag      v1.0.0 created
  tag      v1.0.0 pushed to origin
  github   release created: https://github.com/...
  pypi     building package...
  pypi     upload complete
  snapshot splent_feature_notes@v1.0.0 (read-only)

  splent_io/splent_feature_notes v1.0.0 released.

  Attach splent_feature_notes@v1.0.0 to my_first_app? [Y/n]: y
  attach   linking to product...
    reinstalling in web container...
  done.

At the end, the release asks whether to attach the new version to the active product. Press Y — this pins the release in pyproject.toml (replacing the editable reference) and reinstalls it in the web container automatically.

You can also pass the version explicitly to skip the wizard: splent feature:release splent-io/splent_feature_notes v1.0.0


Step 5 – Pin a version manually (optional)

If you pressed Y at the attach prompt in the previous step, the feature is already pinned. This step is only needed if you skipped the prompt or want to attach a different version later.

To manually pin a released version:

splent feature:attach splent-io/splent_feature_notes v1.0.0

Your product’s pyproject.toml now says splent-io/splent_feature_notes@v1.0.0 instead of splent-io/splent_feature_notes. The feature is pinned – it will not change unless you explicitly upgrade.


Step 6 – Resolve the product

splent product:resolve

This re-creates all symlinks. The notes symlink now points into .splent_cache/ (read-only) instead of the workspace root (editable):

my_first_app/features/splent_io/
  splent_feature_notes@v1.0.0  ->  ../../../.splent_cache/features/splent_io/splent_feature_notes@v1.0.0

Step 7 – Validate the product

splent product:validate

This checks that all UVL constraints are satisfied and all feature contracts are compatible. You should see:

  product:validate -- my_first_app
  ────────────────────────────────

  UVL constraints:    PASS
  Feature contracts:  PASS
  Missing features:   0

  Product is valid.

Part 2 — Deploy to production

This part does not require GitHub or PyPI accounts. You can run it even if you skipped Part 1.

If you skipped Part 1, splent_feature_notes is not published on PyPI. The production build installs features from PyPI, so it will fail on splent_feature_notes. Remove it from your product before building: splent feature:remove splent_feature_notes. The product will deploy with the remaining features (auth, profile, redis, session_redis, public).


Step 8 – Build the production image

splent product:build

This runs pre-flight checks (UVL validation, contract consistency, missing features) and then builds a multi-stage Docker image optimized for production. The image installs pinned features from PyPI, compiles frontend assets with Webpack in production mode, and strips dev dependencies.

At the end, two files are generated in my_first_app/docker/:

  • .env.deploy — production environment variables (database credentials, secret key, Redis URL, etc.). Review and edit this file before deploying.
  • docker-compose.deploy.yml — production Compose file that merges the product and all feature services into a single stack.

Step 9 – Deploy

splent product:deploy

The command prompts for production credentials (database host, Redis URL, secret key) if .env.deploy is not yet configured. Once confirmed, it starts the production containers and runs a health check to verify the app is responding.

Open the URL shown in the terminal and verify the product works — log in, navigate through the features, and confirm everything is functional.


Step 10 – Shut down production

When you are done verifying:

splent product:down --prod

Step 11 – Back to development

Restart the dev environment:

splent product:up --dev
splent product:run --dev

What you learned

Concept What it means
Feature contract Machine-readable summary of routes, models, hooks, services, and dependencies – inferred from source code
Release pipeline One command bumps, tags, publishes to PyPI, and snapshots to cache
Pinned vs editable Editable lives at workspace root (read-write); pinned lives in .splent_cache/ (read-only)
Production deployment Multi-stage Docker build, .env.deploy, and product:deploy
Dev/prod isolation --dev and --prod flags keep environments fully separate

Next

Tutorial 6 – Extend with refinement: override a service, extend a model, and add new routes without forking the base feature.


Back to top

splent. Distributed by an LGPL license v3. Contact us: drorganvidez@us.es