Files
SageTube/.github/workflows/build-linux.yml
T
Your Name 51d9c1d119 Update executable naming in build workflow
Changed the internal executable target name to 'YTSage' instead of including the version. The AppImage filename still includes the version, but the base executable name is now consistent and versionless.
2025-09-02 15:56:00 +03:00

246 lines
7.3 KiB
YAML

name: Build Linux Release
on:
push:
tags:
- 'v*'
permissions:
contents: write
env:
PYTHON_VERSION: '3.13.6'
jobs:
build-linux:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Extract version from tag
id: get_version
shell: bash
run: |
tag="${GITHUB_REF_NAME}"
version="${tag#v}"
echo "Extracted version: $version"
echo "VERSION=$version" >> "$GITHUB_OUTPUT"
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Cache Python dependencies
uses: actions/cache@v3
with:
path: |
venv
~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install system dependencies
shell: bash
run: |
sudo apt-get update -y
# Tools commonly required by cx_Freeze on Linux packaging
sudo apt-get install -y --no-install-recommends \
rpm alien fakeroot patchelf desktop-file-utils file xz-utils zsync
- name: Create virtual environment and install dependencies
shell: bash
run: |
python -m venv venv
source venv/bin/activate
python -m pip install --upgrade pip
pip install --no-cache-dir -r requirements.txt
pip install --no-cache-dir cx_Freeze yt-dlp
- name: Prepare build variables
shell: bash
run: |
version="${{ steps.get_version.outputs.VERSION }}"
echo "VERSION=$version" >> "$GITHUB_ENV"
arch="$(uname -m)" # x86_64 or aarch64
echo "ARCH=$arch" >> "$GITHUB_ENV"
echo "Prepared build variables for version: $version on $(uname -a)"
- name: Create cx_Freeze setup script (Linux)
shell: bash
run: |
cat > setup_cxfreeze.py <<'PY'
import os
from cx_Freeze import setup, Executable
version = os.environ.get("VERSION", "0.0.0")
build_exe_options = dict(
optimize=2,
packages=[
"PySide6.QtCore",
"PySide6.QtGui",
"PySide6.QtWidgets",
"requests",
"PIL",
"packaging",
"markdown",
"pyglet",
"loguru",
"setuptools",
],
excludes=[
"PySide6.QtBluetooth",
"PySide6.QtNetwork",
"PySide6.QtOpenGL",
"PySide6.QtPrintSupport",
"PySide6.QtSvg",
"PySide6.QtTest",
"PySide6.QtXml",
"PySide6.QtSql",
"PySide6.QtHelp",
"PySide6.QtMultimedia",
"PySide6.QtQml",
"PySide6.QtQuick",
"PySide6.QtWebEngineCore",
"PIL.ImageDraw",
"PIL.ImageFont",
"numpy",
"scipy",
"wx",
"pandas",
"tkinter",
"yt_dlp",
"unittest",
"test",
"tests",
],
include_files=[
("src", "src"),
("assets", "assets"),
],
)
executables = [
Executable(
script="main.py",
target_name="YTSage",
icon="assets/branding/icons/icon.png",
)
]
setup(
name="YTSage",
version=version,
description="YTSage",
options={
"build_exe": build_exe_options,
# AppImage packaging
"bdist_appimage": {
# If ends with .AppImage, use verbatim file name
"target_name": f"YTSage-v{version}.AppImage",
# Use the base executable name internally, version in AppImage filename
},
# RPM packaging metadata (minimal)
"bdist_rpm": {
"release": "1",
"group": "Applications/Multimedia",
# Optional: icon can be picked from Executable's icon
},
# DEB packaging wraps alien to convert RPM
"bdist_deb": {},
},
executables=executables,
)
PY
- name: Build AppImage, RPM and DEB
shell: bash
run: |
set -e
source venv/bin/activate
# Ensure a clean build and build_exe first
python setup_cxfreeze.py build_exe
# Remove screenshots to reduce size before packaging
build_dir=$(ls -d build/exe.* 2>/dev/null | head -n1 || true)
if [ -n "$build_dir" ] && [ -d "$build_dir/assets/branding/screenshots" ]; then
rm -rf "$build_dir/assets/branding/screenshots"
echo "Removed screenshots folder from $build_dir"
fi
# Build AppImage
python setup_cxfreeze.py bdist_appimage
# Build RPM
python setup_cxfreeze.py bdist_rpm
# Build DEB (via alien from RPM)
python setup_cxfreeze.py bdist_deb || echo "bdist_deb completed with warnings (alien)"
echo "Post-build directory listing:"
echo "-- dist --"; ls -lah dist || true
echo "-- build --"; ls -lah build || true
- name: Package and prepare release artifacts (.AppImage, .rpm, .deb)
shell: bash
run: |
version="${{ steps.get_version.outputs.VERSION }}"
mkdir -p artifacts
# Copy AppImage
appimage_src=$(ls dist/*.AppImage 2>/dev/null | head -n1 || true)
if [ -n "$appimage_src" ]; then
cp "$appimage_src" "artifacts/YTSage-v${version}.AppImage"
echo "Copied AppImage: $appimage_src -> artifacts/YTSage-v${version}.AppImage"
else
echo "Warning: No .AppImage found in dist/"
fi
# Copy RPM (normalize name)
rpm_src=$(ls dist/*.rpm 2>/dev/null | head -n1 || true)
if [ -n "$rpm_src" ]; then
cp "$rpm_src" "artifacts/YTSage-v${version}.rpm"
echo "Copied RPM: $rpm_src -> artifacts/YTSage-v${version}.rpm"
else
echo "Warning: No .rpm found in dist/"
fi
# Copy DEB (normalize name)
deb_src=$(ls dist/*.deb 2>/dev/null | head -n1 || true)
if [ -n "$deb_src" ]; then
cp "$deb_src" "artifacts/YTSage-v${version}.deb"
echo "Copied DEB: $deb_src -> artifacts/YTSage-v${version}.deb"
else
echo "Warning: No .deb found in dist/"
fi
echo "Final artifacts:"
ls -lh artifacts || true
- name: Create/Update draft release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ github.ref_name }}
name: YTSage ${{ github.ref_name }}
draft: true
prerelease: false
append_body: true
fail_on_unmatched_files: false
body: |
# YTSage ${{ github.ref_name }}
**Release Date**: ${{ github.event.head_commit.timestamp }}
**Full Changelog**: https://github.com/${{ github.repository }}/compare/${{ github.ref_name }}
files: |
artifacts/*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}