Skip to content
ThemeNord

Same themes as the MinusPod app

Default

Catppuccin

Dracula

Nord

Gruvbox

Solarized

Rose Pine

Kanagawa

Ayu

Other

Releasing

MinusPod ships on two channels from the same version line.

Channel Docker tags What it is
Edge latest, <version>, <version>-cpu, cpu Every merged release, several per day at times
Stable stable (GPU), stable-cpu (CPU multi-arch) An edge release that has soaked in production and been promoted

Every release is tagged v<version> and published as a GitHub pre-release whose notes cover every CHANGELOG.md section shipped since the previous release. Usually that is one section; when a PR bumped the version more than once before merging, the notes roll up all of its sections so nothing ships undocumented. The releases page shows the full stream; stable releases are the non-pre-release entries and carry curated, operator-facing notes.

  1. Run scripts/bump_ytdlp.sh so the image ships the latest yt-dlp release as its floor. Commit the ytdlp-version.txt change with the release. Run python3 scripts/security_packages_hash.py --check --resolve, which also verifies the pinned digest’s hash label; a patch-input change needs the security-packages workflow and scripts/bump_security_packages.sh before the GPU build. Release builds pull ttlequals0/minuspod-security-packages.
  2. On the release branch, build the GPU image for linux/amd64. Run the container smoke check below, scan it, and push the version tag. Stop if any GPU step fails.
  3. Dispatch the native multi-architecture CPU workflow from the release branch: gh workflow run cpu-image.yml -f version=X.Y.Z --ref <branch>. Watch the linux/amd64 and linux/arm64 jobs and the manifest merge. CPU and GPU Trivy reports are separate. Record CPU-only findings in the PR; they do not block the GPU release.
  4. Merge the release PR to main with squash subject Short description (X.Y.Z) (#PR) only after both images and required PR checks pass.
  5. On up-to-date main: scripts/publish_release.sh X.Y.Z. This creates the annotated tag and the GitHub pre-release.
  6. Publishing the pre-release triggers the release-tags workflow (.github/workflows/release-tags.yml), which moves latest to the new GPU image and cpu to the new CPU image (waiting up to 10 minutes for the CPU build to finish). The workflow skips itself when the published release is not the newest one, so retroactively publishing an old version never moves the edge tags backwards.

The GPU image is amd64-only. The CPU workflow publishes one manifest for amd64 and arm64 on native GitHub runners. Use promote_cpu_tag=true only for a manual, out-of-band move of :cpu; the normal release flow moves it from the published pre-release.

Promote a release once it has soaked: at least 48 hours running in production, a clean error-log scan, and no open regression reports against it.

  1. Write curated notes covering everything since the previous stable (grouped Breaking changes, New features, Fixes, Upgrade notes) and apply them to the release body.
  2. scripts/promote_release.sh X.Y.Z. This moves the stable and stable-cpu Docker tags with docker buildx imagetools create (no rebuild; the CPU multi-arch manifest is preserved), then flips the pre-release flag.

Container smoke check (before pushing a built image)

Section titled “Container smoke check (before pushing a built image)”

The test suite runs with the repo root on PYTHONPATH, but gunicorn’s boot path inside the container only has /app/src on sys.path (see gunicorn.conf.py). A module-level import that only resolves with the repo root on the path passes the test suite but crash-loops every worker in the container. tests/unit/test_container_import_paths.py catches this in CI by reproducing the narrower boot path in a subprocess, but a build-time check on the real image closes the gap between “the test passed” and “gunicorn actually boots in the built image.”

After building an image locally and before pushing it, run:

docker run --rm --entrypoint python <image> -c "import sys; sys.path.insert(0,'/app/src'); import database, main_app"

If this fails, do not push the image. Investigate the import error (it is almost always a module-level import that only resolves when the repo root is on sys.path) and fix it before rebuilding.

CHANGELOG.md records every version in full technical detail (Keep a Changelog format). Alongside Added, Changed, Fixed, and Removed, a Breaking section marks anything that requires operator action (env var renames, compose changes, manual migration steps). Breaking entries are surfaced at the top of stable release notes.