Skip to contentSkip to content

Packaging and Release

This page is for maintainers. It explains how the project turns source code into distributable desktop and Docker artifacts, how version numbers are determined, how CI publishes to GitHub Releases and container registries, and the boundary of version-check and update-maintenance flows. It does not cover user-facing install and update steps (see Update and version switching), web-server ports and deployment (see Web server ports and deployment), repository module boundaries (see Architecture and code boundaries), or tests and code quality (see Tests and code quality).

Relevant code

  • Version: a v* Git tag (for example v2.2.10) is authoritative. packaging/VERSION is the in-package version file; [project] version in pyproject.toml and the hardcoded VERSION in packaging/launch.py are development markers.
  • Release packages: .github/workflows/build-and-release.yml follows the layout of scripts/manga-translator-ui-portable. It downloads the portable Release as a base, overlays the selected source ref, installs locked CPU, NVIDIA CUDA 13.0 GPU, NVIDIA CUDA 12.6 GPU, or Windows AMD dependencies into bundled Python, installs model files, and creates split archives.
  • Docker: .github/workflows/docker-build-push.yml continues to build and push CPU/GPU images.
  • This guide covers packaging and release only. Module code boundaries, test flows, and web ports/deployment belong to Architecture and code boundaries, Tests and code quality, and Web server ports and deployment respectively.

How to use it

Only two kinds of visible copy relate to packaging and release: the desktop window-title/sidebar version display and the source-install maintenance menu's version-check entry. Neither is a settings-page parameter; the full maintenance-menu workflow lives in Update and version switching.

Version number

Version sources

File/locationCurrent valueRole
packaging/VERSIONv2.2.10 (with v)In-package version-check file; CI writes the release version without v
Git tag v*e.g. v2.2.10CI release source; github.ref_name is written into the portable package
pyproject.toml [project] version1.7.6Project metadata marker; unused by CI releases
packaging/launch.py constant VERSION1.7.6Development banner marker; unused by CI releases

CI strips the leading v from the tag and writes both root VERSION and packaging/VERSION. The package keeps Win-Start.bat, Win-Install-or-Update.bat, bundled Python, uv, and PortableGit.

Version check

Both packaging/check_version.py and launch.py#check_version_info() read the local packaging/VERSION, fetch from the remote, and compare it with origin/<branch>:packaging/VERSION; launch.py also counts the commits behind with HEAD..origin/<branch>. When the fetch fails or the network is unavailable, they honestly report that the remote version could not be obtained instead of misreporting "up to date" using stale origin/* refs.

Portable release build

Build entry

CI no longer publishes the PyInstaller dist/ tree. .github/workflows/build-and-release.yml downloads the portable Release as a base package, using the same directory layout as scripts/manga-translator-ui-portable, then overlays current source.

Each CPU/GPU/AMD matrix job runs these steps in order:

  1. Extract the base package while retaining bundled packaging/python, packaging/uv.exe, and PortableGit.
  2. Overlay current source and write version files.
  3. Export the matching dependency group with uv export --locked, then install it with uv pip install --python packaging/python/python.exe --requirement requirements.txt.
  4. For AMD, remove normal PyTorch and install Radeon ROCm SDK 7.2.1 plus matching PyTorch wheels in the same order as packaging/launch.py.
  5. Download and extract models.7z from Release v1.7.9 into models/.
  6. Import runtime modules for CPU/GPU, validate ROCm wheel metadata for AMD, then create split archives for CPU, default CUDA 13.0 GPU, CUDA 12.6 GPU, and AMD; RTX 50-series users must select one of the NVIDIA GPU archives.

packaging/build_packages.py and the spec files remain available for local PyInstaller debugging, but they are no longer the entry point for this CI release.

Build steps

flowchart LR
    T["v* tag"] --> B["download portable base"]
    B --> S["overlay source and write VERSION"]
    S --> D["uv export --locked + uv pip install"]
    D --> M["extract models.7z"]
    M --> Q["PyQt6/torch/onnxruntime smoke test"]
    Q --> Z["split and upload CPU/GPU/AMD archives"]

Dependency and model installation happen inside the build jobs. The publish job only downloads the three archives, reads the changelog, and creates the GitHub Release.

Release artifacts

Artifact layout

Each release archive is a complete Windows portable directory and does not contain app.exe:

Directory/fileContentNote
Win-Start.batStartup entryRuns the desktop UI with bundled Python
Win-Install-or-Update.batMaintenance entryReinstalls dependencies or updates source
packaging/python/Python 3.12 runtime and installed dependenciesSeparate CPU/GPU/AMD environments
packaging/uv.exe, PortableGit/Portable toolsNo system Python or Git required
config/, fonts/, dict/, doc/Application resourcesReleased with source
models/AI model weightsExtracted from models.7z during the build
VERSIONRelease versionLeading v removed

Split archives

The four assets are named manga-translator-cpu-<tag>.7z.*, manga-translator-cuda13.0-<tag>.7z.*, manga-translator-cuda12.6-<tag>.7z.*, and manga-translator-rocm7.2.1-<tag>.7z.*. The command uses 7z a -v1990m -m0=lzma2 -ms=on; extracting the first volume restores the complete portable directory.

CI release pipeline

Release triggers

build-and-release.yml runs for v* tag pushes and manual dispatch. It deliberately does not listen to release: published, because deleting and recreating a release would otherwise trigger a loop. The Docker workflow remains independent.

Pipeline steps

flowchart LR
    T["v* tag / manual dispatch"] --> C["Windows matrix: cpu, gpu, amd"]
    C --> P["download portable base and overlay source"]
    P --> D["install locked dependencies into bundled Python"]
    D --> M["install model files"]
    M --> A["smoke test + split archive"]
    A --> R["Ubuntu publish job"]
    R --> L["read CHANGELOG"]
    L --> X["delete existing release for the tag"]
    X --> G["create GitHub Release"]

The publish job waits for every matrix job. Before uploading, it deletes any existing GitHub Release for the same tag and then creates the replacement. Any dependency install, model download, runtime import, or archive failure prevents publication.

Docker images

Image build

packaging/Dockerfile is a multi-stage build: base-cpu is based on python:3.12-slim, base-gpu on nvidia/cuda:12.1.0-cudnn8-runtime-ubuntu22.04, selected by the BUILD_TYPE argument. Both stages install system dependencies, run uv sync --locked --no-default-groups --group cpu|gpu, call ensure_runtime_files() to generate runtime config and prompt tables, and back up config, fonts, dict, and server data into default_* directories so the entrypoint can restore them when volumes are mounted empty. The image runs as a web service (MANGA_TRANSLATOR_WEB_SERVER=true, QT_QPA_PLATFORM=offscreen, EXPOSE 8000), its health check requests http://localhost:8000/, and the default command is python -m manga_translator web --host 0.0.0.0 --port 8000.

docker-build-push.yml uses a [cpu, gpu] matrix to build linux/amd64, logs in to Docker Hub and ghcr.io, deletes the current semver tag from Docker Hub and GHCR, and then pushes the replacement image. Tags carry a -cpu/-gpu suffix for branch/PR refs, semver <version> and <major>.<minor>, and latest.

Compose deployment

packaging/docker-compose.yml defines two services: manga-translator-cpu maps host 8000:8000, and manga-translator-gpu maps 8001:8000. Both mount ./data/{fonts,dict,result,models,logs,server,config} into the container, use MT_* environment variables for the web host, port, GPU, model TTL, retries, and verbose logging, and set the admin password through MANGA_TRANSLATOR_ADMIN_PASSWORD (the template ships a default placeholder value that must be replaced on first startup). Uncommenting the ./data/app.env:/app/.env mount keeps API keys saved in the web admin UI across container rebuilds.

Constraints and notes

  • The five hardware backend groups cpu, cuda13.0, cuda12.6, rocm7.2.1, and metal are mutually exclusive; CI builds Windows cpu, cuda13.0, cuda12.6, and rocm7.2.1 portable packages.
  • After locked common dependencies, the ROCm 7.2.1 package installs Radeon ROCm SDK 7.2.1 and matching PyTorch wheels in launcher order; AMD driver 26.2.2 and a supported GPU are required.
  • Release packages already contain locked dependencies and models/; archive size is therefore large and the 1990 MiB split must remain.
  • packaging/VERSION, [project] version in pyproject.toml, and the hardcoded launcher version may differ; the tag-derived VERSION in the package is authoritative for releases.
  • The pipeline depends on the existing portable base asset and v1.7.9/models.7z; either asset missing or failing to download prevents publication.
  • Docker builds exclude doc/, *.md, tests, and build artifacts via packaging/.dockerignore, so the image contains only runtime resources.
  • This page never writes real API keys, tokens, usernames, or private absolute paths; admin-password and environment-variable values in compose are release-template values and are not copied into the documentation.

Developer Guide

Option matrix

Window title and version display

On startup the packaged app reads the VERSION file from runtime resources through desktop_qt_ui/utils/app_version.py#get_app_version() (search order VERSION then packaging/VERSION, strips the v prefix, and falls back to unknown), then appends it to the window title and the Qt application version:

UI call keyEnglish actual valueSimplified Chinese actual value
Manga TranslatorManga Translator漫画翻译器
format_app_title resultManga Translator v2.2.10漫画翻译器 v2.2.10
format_version_label resultv2.2.10v2.2.10

Maintenance menu

Win-Install-or-Update.bat / Unix-Install-or-Update.sh ultimately run packaging/launch.py --maintenance. The menu copy comes from the hardcoded L(Simplified Chinese, English) calls in launch.py, not from en_US.json/zh_CN.json; the table uses the code literal as the key:

UI call keyEnglish actual valueSimplified Chinese actual value
[1] Install (...)Install (detect GPU, choose CPU/GPU build, install dependencies)安装 (检测显卡, 选择 CPU/GPU 版本并安装依赖)
[2] Update (code + dependencies)Update (code + dependencies)更新 (代码+依赖)
[3] Switch branch (main/beta)Switch branch (main/beta)切换分支 (main/beta)
[4] Switch version (by tag)Switch version (by tag)切换版本 (按 tag)
[5] Switch mirrorSwitch mirror切换镜像源
[6] Re-check versionRe-check version重新检查版本
[7] Language (中文/English)Language (中文/English)切换语言 (中文/English)
[8] ExitExit退出
File/directoryRole on this pageNote
packaging/VERSIONAuthoritative version fileCarries the v prefix; read by build and check scripts
packaging/build_packages.pyDesktop packaging entryVersion required; writes back VERSION and build_info.json
packaging/manga-translator-{cpu,gpu}.specPyInstaller specsEntry desktop_qt_ui/main.py, collects runtime data
packaging/Dockerfile, docker-compose.yml, docker-entrypoint.shDocker image and deploymentMulti-stage build, empty-volume restore, health check
packaging/check_version.pyVersion-check scriptCompares origin/main:packaging/VERSION
packaging/launch.pyLauncher and maintenance menu--maintenance, --update, --frozen and more
Win-Start.bat, Win-Install-or-Update.bat, Unix-*.shSource-install entry pointsInvoke launch.py; this guide does not copy their contents
.github/workflows/build-and-release.ymlDesktop release CITag/release triggered; bundling, split archives, Release
.github/workflows/docker-build-push.ymlDocker release CIPushes to Docker Hub and ghcr.io
.github/workflows/docs-pages.ymlWiki site publishingIndependent of desktop releases; deploys doc/wiki only
.github/workflows/sync-to-gitee.ymlRepository mirror syncMirrors branches and tags to Gitee/GitCode on every push
doc/CHANGELOG_v<version>.mdRelease notes bodyRelease body shows a placeholder when missing

Code locations

LayerFileWhat was checked
Versionpackaging/VERSION, packaging/build_packages.py, packaging/check_version.py, desktop_qt_ui/utils/app_version.pyVersion sources, v stripping, write-back, runtime read and display
Desktop packagingpackaging/manga-translator-{cpu,gpu}.spec, pyproject.tomlEntry, data collection, dependency groups and the packaging group
CI release.github/workflows/build-and-release.yml, .github/workflows/docker-build-push.ymlTriggers, build matrix, resource bundling, split archives, Release/image push
Dockerpackaging/Dockerfile, packaging/docker-compose.yml, packaging/docker-entrypoint.sh, packaging/.dockerignoreMulti-stage build, empty-volume restore, ports, health check
Maintenance/updatepackaging/launch.py, Win-*.bat, Unix-*.shMaintenance menu, version check, update and switch
UI/i18ndesktop_qt_ui/main.py, desktop_qt_ui/ui/main_window.py, desktop_qt_ui/locales/en_US.json, zh_CN.jsonWindow-title version composition and visible copy