name: Release on: push: tags: - 'v*' workflow_dispatch: inputs: tag: description: 'Release tag to build (e.g. v9.1.0)' required: true type: string permissions: contents: write id-token: write jobs: build-and-publish: name: Build and publish release artifacts runs-on: ubuntu-latest environment: pypi steps: - name: Checkout repository uses: actions/checkout@v6 - name: Set up Python 3.11 uses: actions/setup-python@v6 with: python-version: '3.11' - name: Install build tool run: | python -m pip install --upgrade pip pip install build - name: Log build environment run: | echo "=== Linux Build Environment ===" echo "OS: $(cat /etc/os-release | grep PRETTY_NAME | cut -d= -f2)" echo "Python: $(python --version)" echo "pip: $(pip --version)" - name: Build sdist & wheel run: | python -m build --sdist --wheel --outdir dist echo "=== Built Artifacts ===" ls -lh dist/ echo "Wheel size: $(du -h dist/*.whl | cut -f1)" - name: Create GitHub Release and upload artifacts uses: ncipollo/release-action@v1 with: tag: ${{ inputs.tag || github.ref_name }} name: Release ${{ inputs.tag || github.ref_name }} artifacts: dist/* skipIfReleaseExists: true - name: Upload dist to actions artifacts uses: actions/upload-artifact@v7 with: name: dist-${{ inputs.tag || github.ref_name }} path: dist/* - name: Publish to PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: verbose: true skip-existing: true distro-packages: name: Build distro packages runs-on: ubuntu-latest needs: build-and-publish steps: - name: Checkout repository uses: actions/checkout@v6 - name: Download wheel from release uses: actions/download-artifact@v8 with: name: dist-${{ inputs.tag || github.ref_name }} path: dist/ - name: Extract version id: version run: | TAG="${{ inputs.tag || github.ref_name }}" echo "ver=${TAG#v}" >> "$GITHUB_OUTPUT" - name: Build RPM (Fedora) run: | docker run --rm \ -v "${{ github.workspace }}:/src" \ -v "${{ github.workspace }}/packages:/output" \ fedora:latest bash -c ' set -e dnf install -y python3-devel python3-hatchling python3-pip python3-installer rpm-build >/dev/null 2>&1 echo "=== RPM Build Environment ===" echo "Fedora: $(cat /etc/fedora-release)" echo "Python: $(python3 --version)" echo "RPM: $(rpm --version)" VER=${{ steps.version.outputs.ver }} WHL=$(ls /src/dist/trcc_linux-*.whl) echo "Wheel: $WHL" PKG=/tmp/buildroot mkdir -p "$PKG" python3 -m installer --destdir="$PKG" --prefix=/usr "$WHL" # Fix shebangs to /usr/bin/python (build container may differ) find "$PKG" -name "trcc*" -path "*/bin/*" -exec sed -i "1s|^#\!.*/python[0-9.]*|#!/usr/bin/python|" {} + # Bundle sounddevice (not in Fedora repos) pip install --root="$PKG" --prefix=/usr --no-deps sounddevice install -Dm644 /src/packaging/udev/99-trcc-lcd.rules "$PKG/etc/udev/rules.d/99-trcc-lcd.rules" install -Dm644 /src/packaging/modprobe/trcc-lcd.conf "$PKG/etc/modprobe.d/trcc-lcd.conf" install -Dm644 /src/packaging/modprobe/trcc-sg.conf "$PKG/etc/modules-load.d/trcc-sg.conf" install -Dm644 /src/src/trcc/assets/trcc-linux.desktop "$PKG/usr/share/applications/trcc-linux.desktop" install -Dm644 /src/src/trcc/assets/com.github.lexonight1.trcc.policy "$PKG/usr/share/polkit-1/actions/com.github.lexonight1.trcc.policy" install -Dm644 /src/src/trcc/assets/trcc-quirk-fix.service "$PKG/usr/lib/systemd/system/trcc-quirk-fix.service" for size in 256 128 64 48 32 24 16; do install -Dm644 /src/src/trcc/assets/icons/trcc_${size}x${size}.png "$PKG/usr/share/icons/hicolor/${size}x${size}/apps/trcc.png" done PYVER=$(python3 -c "import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")") SITELIB="/usr/lib/python${PYVER}/site-packages" cat > /tmp/trcc.spec << SPEC Name: trcc-linux Version: ${VER} Release: 1%{?dist} Summary: Thermalright LCD/LED Control Center for Linux License: GPL-3.0-or-later URL: https://github.com/Lexonight1/thermalright-trcc-linux BuildArch: noarch Requires: python3 Requires: python3-pyside6 Requires: python3-numpy Requires: python3-psutil Requires: python3-pyusb Requires: python3-click Requires: python3-typer Requires: python3-fastapi Requires: python3-uvicorn Requires: python3-prompt-toolkit Requires: portaudio Requires: libusb1 Requires: sg3_utils Recommends: p7zip Recommends: ffmpeg Recommends: python3-pynvml Recommends: python3-dbus Recommends: python3-hidapi %description Controls LCD displays and LED segment displays on Thermalright CPU coolers. %files /etc/udev/rules.d/99-trcc-lcd.rules /etc/modprobe.d/trcc-lcd.conf /etc/modules-load.d/trcc-sg.conf /usr/share/applications/trcc-linux.desktop /usr/share/icons/hicolor/*/apps/trcc.png /usr/share/polkit-1/actions/com.github.lexonight1.trcc.policy /usr/lib/systemd/system/trcc-quirk-fix.service ${SITELIB}/trcc/ ${SITELIB}/trcc_linux-*.dist-info/ ${SITELIB}/sounddevice.py ${SITELIB}/_sounddevice.py ${SITELIB}/__pycache__/sounddevice.* ${SITELIB}/__pycache__/_sounddevice.* ${SITELIB}/sounddevice-*.dist-info/ /usr/bin/trcc /usr/bin/trcc-gui /usr/bin/trcc-detect /usr/bin/trcc-test /usr/bin/trcc-lcd %post udevadm control --reload-rules 2>/dev/null || : udevadm trigger 2>/dev/null || : modprobe sg 2>/dev/null || : SPEC rpmbuild -bb --buildroot="$PKG" --define "_rpmdir /output" /tmp/trcc.spec echo "=== RPM Verification ===" RPM=$(find /output -name "*.rpm" | head -1) echo " Package: $RPM ($(du -h "$RPM" | cut -f1))" rpm -qlp "$RPM" | head -20 echo " Entry points:" rpm -qlp "$RPM" | grep "/usr/bin/" || echo " (none)" echo "RPM build PASSED" ' - name: Build DEB (Ubuntu/Debian) run: | docker run --rm \ -v "${{ github.workspace }}:/src" \ -v "${{ github.workspace }}/packages:/output" \ ubuntu:24.04 bash -c ' set -e apt-get update -qq >/dev/null 2>&1 apt-get install -y -qq python3 python3-pip python3-installer >/dev/null 2>&1 echo "=== DEB Build Environment ===" echo "Ubuntu: $(cat /etc/lsb-release | grep DISTRIB_DESCRIPTION | cut -d= -f2)" echo "Python: $(python3 --version)" echo "dpkg: $(dpkg --version | head -1)" VER=${{ steps.version.outputs.ver }} WHL=$(ls /src/dist/trcc_linux-*.whl) PKG=/tmp/deb-root mkdir -p "$PKG/DEBIAN" python3 -m installer --destdir="$PKG" --prefix=/usr "$WHL" # Fix shebangs to /usr/bin/python (build container may differ) find "$PKG" -name "trcc*" -path "*/bin/*" -exec sed -i "1s|^#\!.*/python[0-9.]*|#!/usr/bin/python|" {} + # Bundle sounddevice (not in Ubuntu/Debian repos) pip install --root="$PKG" --prefix=/usr --no-deps sounddevice install -Dm644 /src/packaging/udev/99-trcc-lcd.rules "$PKG/lib/udev/rules.d/99-trcc-lcd.rules" install -Dm644 /src/packaging/modprobe/trcc-lcd.conf "$PKG/etc/modprobe.d/trcc-lcd.conf" install -Dm644 /src/packaging/modprobe/trcc-sg.conf "$PKG/etc/modules-load.d/trcc-sg.conf" install -Dm644 /src/src/trcc/assets/trcc-linux.desktop "$PKG/usr/share/applications/trcc-linux.desktop" for size in 256 128 64 48 32 24 16; do install -Dm644 /src/src/trcc/assets/icons/trcc_${size}x${size}.png "$PKG/usr/share/icons/hicolor/${size}x${size}/apps/trcc.png" done install -Dm644 /src/src/trcc/assets/com.github.lexonight1.trcc.policy "$PKG/usr/share/polkit-1/actions/com.github.lexonight1.trcc.policy" install -Dm644 /src/src/trcc/assets/trcc-quirk-fix.service "$PKG/lib/systemd/system/trcc-quirk-fix.service" cat > "$PKG/DEBIAN/control" << CTRL Package: trcc-linux Version: ${VER}-1 Section: utils Priority: optional Architecture: all Depends: python3 (>= 3.9), python3-pyside6, python3-numpy, python3-psutil, python3-usb, python3-click, python3-typer, python3-fastapi, python3-uvicorn, python3-prompt-toolkit, libportaudio2, libusb-1.0-0, sg3-utils Recommends: p7zip-full, ffmpeg, python3-pynvml, python3-dbus, python3-hidapi Maintainer: TRCC Linux Contributors Homepage: https://github.com/Lexonight1/thermalright-trcc-linux Description: Thermalright LCD/LED Control Center for Linux Controls LCD displays and LED segment displays on Thermalright CPU coolers and AIO liquid coolers. GUI, CLI, and REST API interfaces. Requires python3-pyside6 in apt — suitable for Debian 13+ and distros that package PySide6 as a system package. For Ubuntu 24.04 use the legacy .deb instead. CTRL cat > "$PKG/DEBIAN/postinst" << POST #!/bin/sh set -e udevadm control --reload-rules 2>/dev/null || true udevadm trigger 2>/dev/null || true modprobe sg 2>/dev/null || true POST chmod 755 "$PKG/DEBIAN/postinst" dpkg-deb --build "$PKG" "/output/trcc-linux_${VER}-1_all.deb" echo "=== DEB Verification ===" DEB="/output/trcc-linux_${VER}-1_all.deb" echo " Package: $DEB ($(du -h "$DEB" | cut -f1))" dpkg-deb -c "$DEB" | grep "/usr/bin/" || echo " (no entry points)" echo "DEB build PASSED" ' - name: Build DEB legacy (Ubuntu 22.04 and older) run: | docker run --rm \ -v "${{ github.workspace }}:/src" \ -v "${{ github.workspace }}/packages:/output" \ ubuntu:22.04 bash -c ' set -e apt-get update -qq >/dev/null 2>&1 apt-get install -y -qq python3 python3-pip >/dev/null 2>&1 echo "=== DEB Legacy Build Environment ===" echo "Ubuntu: $(cat /etc/lsb-release | grep DISTRIB_DESCRIPTION | cut -d= -f2)" echo "Python: $(python3 --version)" echo "dpkg: $(dpkg --version | head -1)" VER=${{ steps.version.outputs.ver }} PKG=/tmp/deb-legacy-root mkdir -p "$PKG/DEBIAN" install -Dm644 /src/packaging/udev/99-trcc-lcd.rules "$PKG/lib/udev/rules.d/99-trcc-lcd.rules" install -Dm644 /src/packaging/modprobe/trcc-lcd.conf "$PKG/etc/modprobe.d/trcc-lcd.conf" install -Dm644 /src/packaging/modprobe/trcc-sg.conf "$PKG/etc/modules-load.d/trcc-sg.conf" install -Dm644 /src/src/trcc/assets/trcc-linux.desktop "$PKG/usr/share/applications/trcc-linux.desktop" for size in 256 128 64 48 32 24 16; do install -Dm644 /src/src/trcc/assets/icons/trcc_${size}x${size}.png "$PKG/usr/share/icons/hicolor/${size}x${size}/apps/trcc.png" done install -Dm644 /src/src/trcc/assets/com.github.lexonight1.trcc.policy "$PKG/usr/share/polkit-1/actions/com.github.lexonight1.trcc.policy" install -Dm644 /src/src/trcc/assets/trcc-quirk-fix.service "$PKG/lib/systemd/system/trcc-quirk-fix.service" cat > "$PKG/DEBIAN/control" << CTRL Package: trcc-linux Version: ${VER}-1~legacy Section: utils Priority: optional Architecture: all Depends: python3 (>= 3.9), python3-pip, python3-venv, libportaudio2, libusb-1.0-0, sg3-utils, libxcb-cursor0 Recommends: p7zip-full, ffmpeg, python3-dbus, python3-gi Maintainer: TRCC Linux Contributors Homepage: https://github.com/Lexonight1/thermalright-trcc-linux Description: Thermalright LCD/LED Control Center for Linux Controls LCD displays and LED segment displays on Thermalright CPU coolers and AIO liquid coolers. Python dependencies are installed into an isolated virtualenv at /opt/trcc-linux — no system Python conflicts. Suitable for Ubuntu 24.04, Ubuntu 22.04, Debian 12, and similar distros. CTRL cat > "$PKG/DEBIAN/postinst" << POST #!/bin/sh set -e python3 -m venv /opt/trcc-linux /opt/trcc-linux/bin/pip install --quiet "trcc-linux==${VER}" for cmd in trcc trcc-gui trcc-detect trcc-lcd trcc-test; do echo "#!/bin/sh" > /usr/bin/\$cmd echo "exec /opt/trcc-linux/bin/\$cmd \"\\\$@\"" >> /usr/bin/\$cmd chmod 755 /usr/bin/\$cmd done udevadm control --reload-rules 2>/dev/null || true udevadm trigger 2>/dev/null || true modprobe sg 2>/dev/null || true POST chmod 755 "$PKG/DEBIAN/postinst" cat > "$PKG/DEBIAN/prerm" << PRERM #!/bin/sh set -e for cmd in trcc trcc-gui trcc-detect trcc-lcd trcc-test; do rm -f /usr/bin/\$cmd done rm -rf /opt/trcc-linux PRERM chmod 755 "$PKG/DEBIAN/prerm" dpkg-deb --build "$PKG" "/output/trcc-linux_${VER}-1.legacy_all.deb" echo "=== DEB Legacy Verification ===" DEB="/output/trcc-linux_${VER}-1.legacy_all.deb" echo " Package: $DEB ($(du -h "$DEB" | cut -f1))" dpkg-deb -I "$DEB" echo "DEB legacy build PASSED" ' - name: Build Arch package run: | docker run --rm \ -v "${{ github.workspace }}:/src" \ -v "${{ github.workspace }}/packages:/output" \ archlinux bash -c ' set -e pacman -Sy --noconfirm python python-pip python-installer python-packaging zstd >/dev/null 2>&1 echo "=== Arch Build Environment ===" echo "Arch: $(cat /etc/arch-release 2>/dev/null || echo rolling)" echo "Python: $(python --version)" echo "pacman: $(pacman --version | head -1)" VER=${{ steps.version.outputs.ver }} WHL=$(ls /src/dist/trcc_linux-*.whl) PKG=/tmp/pkg-root mkdir -p "$PKG/usr" python -m installer --destdir="$PKG" --prefix=/usr "$WHL" # Fix shebangs to /usr/bin/python (build container may differ) find "$PKG" -name "trcc*" -path "*/bin/*" -exec sed -i "1s|^#\!.*/python[0-9.]*|#!/usr/bin/python|" {} + # Bundle uvicorn + sounddevice (not in official Arch repos) pip install --root="$PKG" --prefix=/usr --no-deps uvicorn sounddevice install -Dm644 /src/packaging/udev/99-trcc-lcd.rules "$PKG/usr/lib/udev/rules.d/99-trcc-lcd.rules" install -Dm644 /src/packaging/modprobe/trcc-lcd.conf "$PKG/usr/lib/modprobe.d/trcc-lcd.conf" install -Dm644 /src/packaging/modprobe/trcc-sg.conf "$PKG/usr/lib/modules-load.d/trcc-sg.conf" install -Dm644 /src/src/trcc/assets/trcc-linux.desktop "$PKG/usr/share/applications/trcc-linux.desktop" for size in 256 128 64 48 32 24 16; do install -Dm644 /src/src/trcc/assets/icons/trcc_${size}x${size}.png "$PKG/usr/share/icons/hicolor/${size}x${size}/apps/trcc.png" done install -Dm644 /src/src/trcc/assets/com.github.lexonight1.trcc.policy "$PKG/usr/share/polkit-1/actions/com.github.lexonight1.trcc.policy" install -Dm644 /src/src/trcc/assets/trcc-quirk-fix.service "$PKG/usr/lib/systemd/system/trcc-quirk-fix.service" install -Dm644 /src/LICENSE "$PKG/usr/share/licenses/trcc-linux/LICENSE" INSTALLED_SIZE=$(du -sk "$PKG" | cut -f1) cat > "$PKG/.PKGINFO" << INFO pkgname = trcc-linux pkgver = ${VER}-1 pkgdesc = Thermalright LCD/LED Control Center for Linux url = https://github.com/Lexonight1/thermalright-trcc-linux builddate = $(date +%s) packager = TRCC Linux CI size = ${INSTALLED_SIZE} arch = any license = GPL-3.0-or-later depend = python depend = pyside6 depend = python-numpy depend = python-psutil depend = python-pyusb depend = python-click depend = python-typer depend = python-fastapi depend = python-prompt_toolkit depend = portaudio depend = libusb depend = sg3_utils optdepend = 7zip: theme archive extraction optdepend = ffmpeg: video and GIF playback optdepend = python-pynvml: NVIDIA GPU sensor support optdepend = python-dbus: Wayland session support optdepend = python-gobject: Wayland session support optdepend = python-hidapi: Alternative HID transport INFO cd "$PKG" tar -cf - .PKGINFO * | zstd -o "/output/trcc-linux-${VER}-1-any.pkg.tar.zst" echo "=== Arch Verification ===" ARCHPKG="/output/trcc-linux-${VER}-1-any.pkg.tar.zst" echo " Package: $ARCHPKG ($(du -h "$ARCHPKG" | cut -f1))" tar -tf "$ARCHPKG" | grep "usr/bin/" || echo " (no entry points)" echo "Arch build PASSED" ' - name: Fix package directory permissions run: sudo chown -R "$(id -u):$(id -g)" packages/ - name: Generate SHA256 checksums run: | cd packages find . -type f \( -name "*.rpm" -o -name "*.deb" -o -name "*.pkg.tar.zst" \) \ -exec sh -c 'sha256sum "$1" >> SHA256SUMS.txt' _ {} \; # Also checksum the wheel and sdist for f in ../dist/*; do sha256sum "$f" >> SHA256SUMS.txt done cat SHA256SUMS.txt - name: Create fixed-name aliases for stable download URLs run: | RPM=$(find packages -name "*.rpm" | head -1) DEB=$(find packages -name "*_all.deb" ! -name "*legacy*" | head -1) DEB_LEGACY=$(find packages -name "*legacy*_all.deb" | head -1) ARCH=$(find packages -name "*.pkg.tar.zst" | head -1) cp "$RPM" packages/trcc-linux-latest.noarch.rpm cp "$DEB" packages/trcc-linux-latest_all.deb cp "$DEB_LEGACY" packages/trcc-linux-latest.legacy_all.deb cp "$ARCH" packages/trcc-linux-latest-any.pkg.tar.zst - name: Upload distro packages + checksums to release env: GH_TOKEN: ${{ github.token }} run: | RPM=$(find packages -name "*.rpm" ! -name "*latest*" | head -1) DEB=$(find packages -name "*_all.deb" ! -name "*legacy*" ! -name "*latest*" | head -1) DEB_LEGACY=$(find packages -name "*legacy*_all.deb" ! -name "*latest*" | head -1) ARCH=$(find packages -name "*.pkg.tar.zst" ! -name "*latest*" | head -1) gh release upload "${{ inputs.tag || github.ref_name }}" \ "$RPM" "$DEB" "$DEB_LEGACY" "$ARCH" \ packages/trcc-linux-latest.noarch.rpm \ packages/trcc-linux-latest_all.deb \ packages/trcc-linux-latest.legacy_all.deb \ packages/trcc-linux-latest-any.pkg.tar.zst \ packages/SHA256SUMS.txt \ --clobber