feat(packaging): build thin .deb and .rpm and attach them to releases (#913)
* feat(packaging): build thin .deb and .rpm with nfpm and attach them to releases Adds packaging/native: an nfpm config that produces a .deb and an .rpm from the release wheel. The packages stay thin - Python, GTK, PyGObject and the typelibs are distro Depends; only pywhispercpp and pynput are vendored because the first is unpackaged on both distros and the second is missing on Fedora. The Debian 12 build image and the nfpm download are pinned in tool_checksums.txt. just native-packages builds both in the pinned container, and native-smoke installs the built package per distro: debian:12 and ubuntu:24.04 exercise the .deb, fedora:42 the .rpm, then each runs vocalinux --version plus an import smoke of the app and the vendored extension. unified-pipeline.yml gates on the same three-distro matrix, and release.yml attaches both arches to the release and covers them in SHA256SUMS and the provenance manifest. Refs #600 * fix(packaging): preserve launcher args and document Wayland input group The launcher joined $* into an unquoted exec, re-splitting file paths that contain spaces before argparse saw them. Exec "$@" directly and re-quote each argument for the inner shell of 'sg input -c'. On Wayland the packages could not grant the 'input' group membership evdev hotkeys need; name the usermod step and its caveat in INSTALL.md and the release notes. * test(packaging): add return types to the native packaging tests --------- Co-authored-by: Jatin K Malik <jatinkrmalik@gmail.com>
This commit is contained in:
co-authored by
Jatin K Malik
parent
d53300841d
commit
4b7d57c077
@@ -257,6 +257,26 @@ jobs:
|
||||
```
|
||||
Still requires `xdotool`/`wtype`/`ydotool` on the host for text injection, same as the PyPI path.
|
||||
|
||||
### Distro packages (.deb / .rpm)
|
||||
Download the package matching your distro and CPU (`amd64`/`x86_64`, or `arm64`/`aarch64`
|
||||
attached shortly after this release is published):
|
||||
```bash
|
||||
# Debian / Ubuntu
|
||||
sudo apt install ./vocalinux_*_amd64.deb
|
||||
|
||||
# Fedora
|
||||
sudo dnf install ./vocalinux-*.x86_64.rpm
|
||||
```
|
||||
Thin packages: Python, GTK, PyGObject and the AppIndicator typelib come from the
|
||||
distro, and `apt`/`dnf` resolves them. Only `pywhispercpp` and `pynput` are
|
||||
vendored (the first is packaged by neither distro, the second is missing on
|
||||
Fedora). whisper.cpp runs on CPU in these packages; the Vulkan build is the
|
||||
AppImage. A PPA and a COPR are not published yet.
|
||||
|
||||
On Wayland the default Right Alt hotkey uses evdev: `sudo usermod -aG input $USER`,
|
||||
then log out and back in (the `input` group can read every keyboard and pointer
|
||||
device; X11 needs nothing).
|
||||
|
||||
${{ steps.flatpak_notes.outputs.flatpak }}
|
||||
|
||||
### Snap
|
||||
@@ -353,6 +373,104 @@ jobs:
|
||||
--repo ${{ github.repository }} \
|
||||
--clobber
|
||||
|
||||
# The .deb and .rpm are thin: they depend on the distro's Python, GTK,
|
||||
# PyGObject and typelibs and vendor only pywhispercpp and pynput (#600).
|
||||
# nfpm builds both from one config inside the pinned Debian 12 image, and
|
||||
# the same wheel PyPI ships is the payload.
|
||||
build-native:
|
||||
name: Build native packages (x86_64)
|
||||
needs: build-and-release
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Extract version from tag
|
||||
id: get_version
|
||||
run: |
|
||||
VERSION=${GITHUB_REF#refs/tags/v}
|
||||
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
|
||||
|
||||
# Same reason the aarch64 AppImage downloads the artifact: one wheel,
|
||||
# everywhere, or the checksums cannot describe what the packages hold.
|
||||
- name: Download the built distributions
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: python-dist
|
||||
path: dist
|
||||
|
||||
- name: Build .deb and .rpm
|
||||
run: |
|
||||
bash packaging/native/docker-build.sh dist/*.whl "${{ steps.get_version.outputs.VERSION }}" dist
|
||||
ls -la dist/*.deb dist/*.rpm
|
||||
|
||||
- name: Upload the x86_64 packages
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: native-x86_64
|
||||
path: |
|
||||
dist/*.deb
|
||||
dist/*.rpm
|
||||
if-no-files-found: error
|
||||
retention-days: 7
|
||||
|
||||
- name: Attach to release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh release upload "${{ github.ref_name }}" \
|
||||
dist/*.deb dist/*.rpm \
|
||||
--repo ${{ github.repository }} \
|
||||
--clobber
|
||||
|
||||
build-native-arm64:
|
||||
name: Build native packages (aarch64)
|
||||
needs: build-and-release
|
||||
runs-on: ubuntu-24.04-arm
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Extract version from tag
|
||||
id: get_version
|
||||
run: |
|
||||
VERSION=${GITHUB_REF#refs/tags/v}
|
||||
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Download the built distributions
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: python-dist
|
||||
path: dist
|
||||
|
||||
- name: Build .deb and .rpm (aarch64)
|
||||
run: |
|
||||
bash packaging/native/docker-build.sh dist/*.whl "${{ steps.get_version.outputs.VERSION }}" dist
|
||||
ls -la dist/*.deb dist/*.rpm
|
||||
|
||||
- name: Upload the aarch64 packages
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: native-aarch64
|
||||
path: |
|
||||
dist/*.deb
|
||||
dist/*.rpm
|
||||
if-no-files-found: error
|
||||
retention-days: 7
|
||||
|
||||
- name: Attach to release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh release upload "${{ github.ref_name }}" \
|
||||
dist/*.deb dist/*.rpm \
|
||||
--repo ${{ github.repository }} \
|
||||
--clobber
|
||||
|
||||
# Pins match .github/workflows/flatpak.yml. These jobs start with the tag
|
||||
# (no needs) so they overlap the wheel / x86_64 AppImage job. The builder
|
||||
# image is Freedesktop SDK, not a GitHub-hosted runner: no `gh`, so attach
|
||||
@@ -656,12 +774,13 @@ jobs:
|
||||
--repo ${{ github.repository }} \
|
||||
--clobber
|
||||
|
||||
# Runs last because the aarch64 AppImage, both Flatpak bundles, and the snap
|
||||
# land after the release is created: a checksum manifest that covers some of
|
||||
# the files is worse than none, since the missing one looks like the tampered one.
|
||||
# Runs last because the aarch64 AppImage, both Flatpak bundles, the native
|
||||
# packages, and the snap land after the release is created: a checksum
|
||||
# manifest that covers some of the files is worse than none, since the
|
||||
# missing one looks like the tampered one.
|
||||
publish-checksums:
|
||||
name: Checksums and Provenance
|
||||
needs: [build-and-release, build-appimage-arm64, build-flatpak-amd64, build-flatpak-arm64, attach-flatpak, attach-snap]
|
||||
needs: [build-and-release, build-appimage-arm64, build-native, build-native-arm64, build-flatpak-amd64, build-flatpak-arm64, attach-flatpak, attach-snap]
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -681,7 +800,7 @@ jobs:
|
||||
ls -la
|
||||
# Bare names, so `sha256sum -c` works in whatever directory the user
|
||||
# downloaded the release into.
|
||||
sha256sum -- *.whl *.tar.gz *.AppImage *.flatpak *.snap | tee SHA256SUMS
|
||||
sha256sum -- *.whl *.tar.gz *.AppImage *.deb *.rpm *.flatpak *.snap | tee SHA256SUMS
|
||||
|
||||
# Attesting from the manifest rather than a second glob: the file we
|
||||
# publish and the set we attest cannot drift apart.
|
||||
|
||||
@@ -24,6 +24,7 @@ jobs:
|
||||
web: ${{ steps.filter.outputs.web }}
|
||||
python: ${{ steps.filter.outputs.python }}
|
||||
aur: ${{ steps.filter.outputs.aur }}
|
||||
native: ${{ steps.filter.outputs.native }}
|
||||
deploy_website: ${{ steps.deploy_check.outputs.deploy }}
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
@@ -66,6 +67,13 @@ jobs:
|
||||
aur:
|
||||
- 'packaging/aur/**'
|
||||
- '.github/workflows/unified-pipeline.yml'
|
||||
# Same carve-out for the .deb/.rpm gate: nfpm.yaml mirrors
|
||||
# pyproject.toml's dependencies against distro package names, so a
|
||||
# native-only change runs its own build and smoke without the
|
||||
# python matrix.
|
||||
native:
|
||||
- 'packaging/native/**'
|
||||
- '.github/workflows/unified-pipeline.yml'
|
||||
- name: Check if website should deploy
|
||||
id: deploy_check
|
||||
env:
|
||||
@@ -360,6 +368,76 @@ jobs:
|
||||
archlinux:latest \
|
||||
bash /repo/packaging/aur/build-test.sh
|
||||
|
||||
# The .deb and .rpm exist to be installed and run, so the gate does exactly
|
||||
# that: build both in the pinned Debian 12 image release.yml uses, then
|
||||
# install them in distro containers and run vocalinux --version plus an
|
||||
# import smoke. debian:12 and ubuntu:24.04 exercise the .deb's dependency
|
||||
# list (and the vendored cp311/cp312 wheels), fedora:42 the .rpm's.
|
||||
native-build:
|
||||
name: 📦 Build native packages (x86_64)
|
||||
runs-on: ubuntu-latest
|
||||
needs: changes
|
||||
if: needs.changes.outputs.python == 'true' || needs.changes.outputs.native == 'true'
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
||||
with:
|
||||
python-version: '3.11'
|
||||
cache: 'pip'
|
||||
|
||||
- name: Build wheel
|
||||
run: |
|
||||
python -m pip install --upgrade pip build
|
||||
python -m build
|
||||
ls -la dist/
|
||||
|
||||
- name: Build .deb and .rpm
|
||||
run: |
|
||||
VERSION=$(grep -oP '__version__\s*=\s*"\K[^"]+' src/vocalinux/version.py)
|
||||
WHEEL=$(ls dist/*.whl)
|
||||
bash packaging/native/docker-build.sh "$WHEEL" "$VERSION" dist
|
||||
ls -la dist/*.deb dist/*.rpm
|
||||
|
||||
- name: Upload the x86_64 packages
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: native-x86_64
|
||||
path: |
|
||||
dist/*.deb
|
||||
dist/*.rpm
|
||||
retention-days: 7
|
||||
|
||||
native-smoke:
|
||||
name: 🐧 Install native package (${{ matrix.distro }})
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changes, native-build]
|
||||
if: needs.changes.outputs.python == 'true' || needs.changes.outputs.native == 'true'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
distro:
|
||||
- debian:12
|
||||
- ubuntu:24.04
|
||||
- fedora:42
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Download the packages built above
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: native-x86_64
|
||||
path: dist
|
||||
|
||||
- name: Install and smoke on ${{ matrix.distro }}
|
||||
run: |
|
||||
docker run --rm \
|
||||
-v "$PWD/dist:/out:ro" \
|
||||
-v "$PWD/packaging/native:/pk:ro" \
|
||||
"${{ matrix.distro }}" \
|
||||
bash /pk/smoke-test.sh
|
||||
|
||||
web-build:
|
||||
name: 🌐 Build Website
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
Reference in New Issue
Block a user