Skip to content

feat: build the .deb and draft a GitHub release on tag push - #102

Merged
Xpiatio merged 1 commit into
mainfrom
feat/release-workflow
Aug 8, 2026
Merged

feat: build the .deb and draft a GitHub release on tag push#102
Xpiatio merged 1 commit into
mainfrom
feat/release-workflow

Conversation

@Xpiatio

@Xpiatio Xpiatio commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Why

v1.9.0 was tagged and pushed on 2026-08-08. Both CI workflows passed, and no release exists and no .deb was ever produced — because the repo has never had release automation. .github/workflows/ holds only ci.yml and version-sync.yml; neither builds an artifact. Every release from v1.0.0 through v1.8.0 was built locally and uploaded by hand.

The intent was already half there: scripts/check_version_sync.py defines check_tag_matches(), which reads GITHUB_REF and fails when a refs/tags/vX.Y.Z ref disagrees with gmrs_tty.__version__. Nothing has ever run it under a tag ref. This gives it a caller.

What

.github/workflows/release.yml — on a v* tag push (or workflow_dispatch with a tag input), a single ubuntu-latest job checks the tag against the tree, fetches the Whisper model and the Piper voices, builds the deb, checks it against the asset budget, and opens a draft release with the deb attached.

workflow_dispatch is how v1.9.0 gets shipped: the tag already exists, and re-pushing it to trigger a build would rewrite release history.

Draft, not published. Release titles here are hand-written (v1.9.0 — Tabbed settings, ...). The workflow does the slow mechanical half; the title and notes stay human.

scripts/voices.txt + scripts/fetch-voices.shModels/ and Voices/ are both gitignored, but build-deb.sh hard-fails without them, and a runner starts with neither. The STT side already had bootstrap_models.py; the voices side had nothing. The manifest is now the single source of truth for what ships, and the fetch script downloads it into Voices/. It skips files already present, so it is safe to run locally, and it downloads through a .part file so an interrupted run cannot leave a truncated voice that the next run happily skips.

scripts/build-deb.sh — honors a PYTHON env override ahead of the .venv / python3.13 / python3 fallbacks, since a runner has neither a .venv nor a python3.13 on PATH. Also drops two stale claims the deb outgrew several releases ago: the header comment saying the models are NOT bundled (sections 2c/2d have bundled both for a while) and the control Description advertising a speaker-identification model that no source file references.

tests/unit/test_voices_manifest.py — offline, no network. Validates the manifest shape and no duplicate basenames, checks the fetch script is executable and reads the manifest, and pins the two comment fixes against drifting back.

Verification

Run locally on this branch:

  • flake8 gmrs_tty tests scripts bootstrap_models.py clean; pytest 1129 passed
  • check_version_sync.py with GITHUB_REF=refs/tags/v1.9.0 exits 0; with refs/tags/v1.8.0 exits 1 — tag v1.8.0 does not match gmrs_tty.__version__ 1.9.0
  • fetch-voices.sh against the existing Voices/ skips all 10 files, exit 0. Against an empty directory it fetches all 5 pairs non-empty. All five .onnx URLs return HTTP 206 on a ranged probe.
  • PYTHON=.venv/bin/python ./scripts/build-deb.sh produces gmrs-tty_1.9.0_amd64.deb, 1,632,666,144 bytes (1.52 GiB). dpkg-deb -I shows Version: 1.9.0 and the corrected Description.

Size context: 1.63 GB against v1.8.0's 1.61 GB, so torch is still resolving CPU-only.

Risks

build-deb.sh relies on --extra-index-url .../whl/cpu winning because 2.x.y+cpu sorts above PyPI's 2.x.y under PEP 440 local-version ordering. That has held, but a version skew between the two indexes would silently pull ~2 GB of nvidia-* wheels. The 1.9 GiB size guard turns that into a loud CI failure instead of a release asset that blows the 2 GB per-asset limit. If it fires, the fix is a +cpu constraints file. The other lever on asset size is trimming scripts/voices.txt.

After merge

gh workflow run release.yml -f tag=v1.9.0, then edit the draft's title to the usual v1.9.0 — <highlights> form and publish. Untested on CI until this lands on mainworkflow_dispatch needs the workflow file on the default branch.

🤖 Generated with Claude Code

Every release from v1.0.0 to v1.8.0 was built and uploaded by hand, and
v1.9.0 was tagged on 2026-08-08 without one: the tag pushed, CI went
green, and nothing produced an artifact, because the repo has only ever
had ci.yml and version-sync.yml. Neither builds anything.

Add .github/workflows/release.yml, triggered by a vX.Y.Z tag push or by
workflow_dispatch with a tag input. The dispatch path exists so tags that
predate this workflow (v1.9.0 among them) can be shipped without deleting
and re-pushing a tag. The job checks the tag against gmrs_tty.__version__
before it spends ten minutes on wheels, which finally gives
check_version_sync.check_tag_matches() a caller -- it reads GITHUB_REF and
has never run under a tag ref until now.

Building on a runner needed two gaps closed. Models/ and Voices/ are both
gitignored but build-deb.sh hard-fails without them: the STT side already
had bootstrap_models.py, the voices side had nothing, so add
scripts/voices.txt as the manifest of what ships and scripts/fetch-voices.sh
to download it. The script is idempotent and writes through a .part file,
so an interrupted run cannot leave a truncated voice that the next run
skips. build-deb.sh now honors a PYTHON override, since a runner has
neither a .venv nor a python3.13 on PATH.

The workflow drafts the release rather than publishing it. Release titles
here are hand-written ("v1.9.0 - Tabbed settings, ..."), so it does the
slow mechanical half and leaves the title and notes to a human.

A size guard fails the build past 1.9 GiB. build-deb.sh leans on
--extra-index-url .../whl/cpu winning on PEP 440 local-version ordering to
keep torch CPU-only; if a version skew between the indexes ever pulls the
nvidia-* wheels instead, that is a loud CI failure rather than a release
asset that silently blows the 2 GB limit.

Also drop two stale claims the deb outgrew several releases ago: the
header comment saying the models are NOT bundled, and the control
Description advertising a speaker-identification model that no source file
references. tests/unit/test_voices_manifest.py validates the manifest
offline and pins both fixes against drifting back.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Xpiatio
Xpiatio merged commit 2db28fb into main Aug 8, 2026
3 checks passed
@Xpiatio
Xpiatio deleted the feat/release-workflow branch August 8, 2026 16:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant