product:release

Table of contents

  1. Introduction
  2. What a release does
  3. Releasing a given version or product
  4. Releasing while you develop
  5. Leaving a channel out
  6. Releasing in an emergency
  7. Finishing a release that stopped
  8. Waiting out PyPI’s new-project limit
  9. Fixing a refused release
    1. Every feature must be pinned
    2. A clone must be able to deploy
  10. Image registries
    1. The stable tag
  11. Publishing to an official repository
  12. Reference
    1. Options
    2. The release commit
    3. The image
    4. Errors
    5. Credentials
  13. Requirements
  14. See also

Introduction

product:release publishes a new version of your product. It bumps the version, commits the deploy bundle for it, and publishes the package to PyPI, the tag and a release page to the forge, and the image to your registries. A clone of the tag then deploys with docker compose alone.

splent product:release
  validate UVL configuration is satisfiable
  contract no conflicts detected
  features  all 7 feature(s) versioned and on PyPI
  Reading the current version...
  Current version: v1.0.3

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

  Choice: 1

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

  Releasing my_first_app v1.0.4

  Release gate (channels)
  forge    ready, my-org/my_first_app accepts push, tag and release as drorganvidez
  pypi     ready, credentials accepted, my_first_app exists so this is a new version
  docker   ready, credentials accepted for git.splent.io/my-org/my_first_app

  Pre-release checks (lint + tests)
  ...

  Re-checking the channels, right before publishing
  ...

  version  1.0.4 written to pyproject.toml
  ...
  lock     45 third-party package(s) pinned in docker/requirements.lock
  commit   changes committed locally
  pypi     upload complete
  push     origin/main updated
  tag      v1.0.4 pushed to origin
  forge    release created https://git.splent.io/my-org/my_first_app/releases/tag/v1.0.4
  docker   git.splent.io/my-org/my_first_app:1.0.4, git.splent.io/my-org/my_first_app:stable
  docker   push complete

  index    marketplace index rebuild requested, so this version appears there within a couple of minutes.
  my_first_app v1.0.4 released.

The wizard offers the next patch, minor and major version. Build, deploy and release tells this command apart from product:build and product:deploy.


What a release does

The steps of a product release and its three channels, in order CHECKS, NOTHING CHANGES Guards pinned, deployable Credentials set in the environment Channel gate then lint and tests Channel gate again the one that counts ON THIS MACHINE Bump the version [project].version Write the bundle deploy/, the pins, the lock Commit the release commit CHANNELS, IN THIS ORDER PyPI the package, permanent Forge push main, tag, release page Image registries the version and stable tags A failure after PyPI leaves the channels diverged, and release:resume finishes them without a new bump.
Nothing changes until the second gate passes. PyPI goes first because a PyPI version can never be replaced.

Nothing changes until the checks pass. The release first refuses a product it cannot reproduce (see Fixing a refused release), then checks your credentials and asks every channel whether it would accept this version. It runs lint and product:test, and asks the channels again right before publishing.

Then it writes [project].version, writes the release commit and publishes in a fixed order. PyPI goes first, because a PyPI version can never be replaced. The forge comes next with main, the tag v<version> and the release page, and the image comes last.


Releasing a given version or product

splent product:release v1.0.4
splent product:release v1.0.4 --product other_app

Pass the version and the wizard does not ask. --product releases that product, and runs its tests, whichever one is selected.


Releasing while you develop

A release is what is committed. So when your checkout lists features with no version and HEAD pins them all, you can release as usual.

splent product:release
  checkout my_app has editable features, so this works from what HEAD holds (3f2a91c08b1d).

The release runs in a temporary workspace holding HEAD. Afterwards your checkout moves forward to the release commit and keeps your pyproject.toml, with the new version in it. Anything else you left uncommitted stays out of the release and stays in your checkout.

If your checkout cannot move, because a file you changed is one the release changed too, it stays as it was and the release tells you what to run once it can.

The release’s tests run in your development stack, so they test what it loads, your working copies included. The CI tests the pinned releases.


Leaving a channel out

splent product:release --no-docker
splent product:release --no-pypi
splent product:release --no-forge

--no-docker publishes no image, and a warning says so. The bundle of that version then builds its image from the repository.

--no-pypi and --no-forge leave this version off PyPI or off the forge for good, so the release asks you to confirm. With --no-forge the commit and the tag stay on your machine.


Releasing in an emergency

splent product:release v1.0.5 --skip-checks

--skip-checks skips lint and tests. The guards and the channel gate still run.


Finishing a release that stopped

When a step after the PyPI upload fails, the channels have diverged. The release says so and prints the command that finishes the rest, image included, without a new bump.

  The channels have DIVERGED for this version. Finish it, without bumping the version, with
    splent release:resume product:my_first_app

The command names the product and carries --no-pypi, --no-forge and --no-docker when the run used them. Until it runs, the gate refuses a new release of the product. --allow-unfinished releases anyway.


Waiting out PyPI’s new-project limit

splent product:release --wait

The first release of a product creates its PyPI project, and PyPI limits how many you create per hour. When the budget is spent, the release waits up to about an hour with a countdown, or stops before changing anything and says when to come back. --wait waits however long it takes. See PyPI new-project limits.


Fixing a refused release

Two guards run first, before any credential is read, and a refusal leaves the product as it was.

Every feature must be pinned

  Cannot release: the following features are editable (no version pinned):

    - splent-io/splent_feature_notes  (in [tool.splent].features)

  A product release must be reproducible. Pin all features first:
    splent feature:release <feature>
    splent feature:attach <feature> <version>

It refuses when HEAD has editable features too. When only your checkout has them, see Releasing while you develop. This covers features, features_dev and features_prod. Release the feature and pin it with feature:attach, or pin every editable one with feature:pin.

A clone must be able to deploy

A clone of the tag has to deploy and build the image on its own. Each refusal starts with Cannot release and says what to do.

Fails when Fix
The product does not pass the checks of product:build Fix what they report
A pinned feature is not in .splent_cache or not linked in <product>/features/ Run splent product:resolve
PyPI does not serve the workspace’s framework or the running CLI Release it first
docker/Dockerfile.<product>.prod cannot build from the repository Run splent product:sync-template <product> --docker and commit it
.gitignore matches deploy/, docker/requirements.lock, docker/frontend.lock.json, splent.contracts.json or docker/spl/ Remove the rules that match

Image registries

[tool.splent.release]
registries = ["forge"]
mirrors = ["dockerhub"]

The image goes to every registry in registries, forge by default, and to the mirrors it can reach, in the table of your release channels.

Name Image Tags Login
forge <forge host>/<org>/<product>, the organization of origin lowercased <version>, stable SPLENT_FORGE_TOKEN, as SPLENT_FORGE_USER or the token’s account
dockerhub <DOCKERHUB_USERNAME>/<product> <version>, stable, latest DOCKERHUB_USERNAME and DOCKERHUB_PASSWORD

A registry is required. The channel gate blocks the release until it accepts the credentials and does not hold <version> yet. The forge token needs the package write scope, write:package on Forgejo (see the forge token).

  docker   blocked, git.splent.io rejected the credentials (HTTP 401)
           SPLENT_FORGE_TOKEN is invalid, expired or lacks the package scope. Run 'splent tokens:setup' for instructions on obtaining tokens.

A mirror is best effort. When its credentials are missing or its login or push fails, it is left out with a warning and the release goes on.

The stable tag

stable moves only when a release publishes, so a host that runs <image>:stable only runs released versions. The deploy bundle runs that tag by default, through SPLENT_IMAGE in deploy/.env.


Publishing to an official repository

When your product’s public home is not the forge, a release can reach it too.

[tool.splent.release.source_mirror]
url = "https://github.com/org/repo"
branches = ["main", "develop"]

The release moves those branches to the commit of its tag, pushes the tag and creates the release there, before it pushes the image. That way a version never reaches production before the page your app links to. branches is main when you leave it out.

A branch only moves forward. The channel gate blocks the release when a branch there has commits your repository lacks, and says how to bring them in.

git fetch git@github.com:org/repo.git main
git merge FETCH_HEAD

Use git merge -s ours FETCH_HEAD when your repository’s tree is the one that stands.

If that repository is down, leave it out and finish it later.

splent product:release --no-mirror
splent release:resume product:<product>

Reference

Options

Option Description
VERSION The version to release, such as v1.2.1. Without it the wizard asks
--product NAME Release this product instead of the selected one
--skip-checks Skip lint and tests
--no-pypi Publish nothing to PyPI for this version. Asks you to confirm
--no-forge Push nothing to the forge. Asks you to confirm
--no-docker Build and push no image
--no-mirror Do not publish to the official repository now
--allow-unfinished Release even though the previous version never finished publishing
--wait Wait however long PyPI’s new-project limit takes

The release commit

The release writes what product:build writes, for the new version, and commits it with the bump. Files that were untracked when the release started stay out.

What Detail
deploy/ The bundle. With an image, it runs <registry>/<org>/<product>:stable from the first release on
[tool.splent.runtime] The framework and CLI the image installs
splent.contracts.json, docker/spl/, docker/frontend.lock.json What the image reads and checks
docker/requirements.lock Resolved afresh, so each release picks up PyPI’s fixes. Left as it is with --no-docker

The image

The image is the build of product:build, made once with every tag from the files of the commit at HEAD. A file git does not track never reaches it, so a registry serves exactly what a clone of the tag builds. No .env file but the *.example templates reaches it.

Errors

Message What to do
Missing required environment variables Set the credentials it lists
no version under [project] Add version under [project] in pyproject.toml
registries is empty, or an unknown registry Remove the key, or name forge or dockerhub
the image's build stage did not build Nothing was committed. Undo the bump in pyproject.toml, or release again
production Dockerfile not found Run splent product:sync-template
could not log into <registry>, the push to <registry> failed Fix its credentials, then run release:resume
mirror blocked Follow what it says. Nothing has changed yet
<tag> on <url> and DIVERGED Fix what it names, then run release:resume

A push or fetch never waits for a password and gives up after 10 minutes.

Credentials

Variable Needed Description
TWINE_USERNAME or PYPI_USERNAME Unless --no-pypi PyPI user
TWINE_PASSWORD or PYPI_PASSWORD Unless --no-pypi PyPI API token
SPLENT_FORGE_TOKEN Unless --no-forge, and for the image while forge is a registry Forge token with the package write scope. GITHUB_TOKEN is read when it is unset
SPLENT_FORGE_USER No The account of the forge registry login
DOCKERHUB_USERNAME, DOCKERHUB_PASSWORD When dockerhub is a registry Docker Hub login. A mirror without them is left out

Check them before you release with splent check:forge and splent check:pypi.


Requirements

  • A selected product (SPLENT_APP), or --product.
  • Every feature pinned, the credentials above, and Docker unless --no-docker.

See also


Back to top

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