47b2ad5cf8
Bump actions/checkout to v5, actions/setup-python to v6, and actions/cache to v4 in build workflows for Linux, macOS, and Windows. This ensures the workflows use the latest features and security updates from GitHub Actions.
259 lines
8.3 KiB
YAML
259 lines
8.3 KiB
YAML
name: Build macOS Release
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
- 'v*'
|
|
|
|
permissions:
|
|
contents: write
|
|
|
|
env:
|
|
PYTHON_VERSION: '3.13.6'
|
|
|
|
jobs:
|
|
build-macos:
|
|
strategy:
|
|
matrix:
|
|
os: [macos-14, macos-13]
|
|
runs-on: ${{ matrix.os }}
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v5
|
|
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@v6
|
|
with:
|
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
|
|
- name: Cache Python dependencies
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: |
|
|
venv
|
|
~/.cache/pip
|
|
~/Library/Caches/pip
|
|
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-pip-
|
|
|
|
- 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 dmgbuild yt-dlp
|
|
|
|
- name: Prepare build variables
|
|
shell: bash
|
|
run: |
|
|
version="${{ steps.get_version.outputs.VERSION }}"
|
|
echo "VERSION=$version" >> "$GITHUB_ENV"
|
|
arch="$(uname -m)" # arm64 or x86_64
|
|
echo "ARCH=$arch" >> "$GITHUB_ENV"
|
|
if [ "$arch" = "arm64" ]; then
|
|
echo "ARCH_SUFFIX=arm64" >> "$GITHUB_ENV"
|
|
else
|
|
echo "ARCH_SUFFIX=x64" >> "$GITHUB_ENV"
|
|
fi
|
|
echo "Prepared build variables for version: $version on $(uname -a)"
|
|
|
|
- name: Create cx_Freeze setup script
|
|
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", "lib/assets"),
|
|
],
|
|
)
|
|
|
|
executables = [
|
|
Executable(
|
|
script="main.py",
|
|
target_name=f"YTSage-v{version}",
|
|
icon="assets/branding/icons/icon.icns",
|
|
)
|
|
]
|
|
|
|
setup(
|
|
name="YTSage",
|
|
version=version,
|
|
description="YTSage",
|
|
options={
|
|
"build_exe": build_exe_options,
|
|
"bdist_mac": {
|
|
"iconfile": "assets/branding/icons/icon.icns",
|
|
"bundle_name": f"YTSage-v{version}",
|
|
},
|
|
"bdist_dmg": {
|
|
"volume_label": f"YTSage v{version}",
|
|
"applications_shortcut": True,
|
|
# Sensible defaults; can be customized later if desired
|
|
"format": "UDZO",
|
|
"filesystem": "HFS+",
|
|
"default_view": "icon-view",
|
|
},
|
|
},
|
|
executables=executables,
|
|
)
|
|
PY
|
|
|
|
- name: Build .app bundle (bdist_mac)
|
|
shell: bash
|
|
run: |
|
|
source venv/bin/activate
|
|
python setup_cxfreeze.py bdist_mac
|
|
# Locate the built .app (cx_Freeze may place it under build/ or dist/)
|
|
app_path=""
|
|
for cand in "dist/YTSage-v${VERSION}.app" "build/dist/YTSage-v${VERSION}.app" "build/YTSage-v${VERSION}.app"; do
|
|
if [ -d "$cand" ]; then app_path="$cand"; break; fi
|
|
done
|
|
if [ -z "$app_path" ]; then
|
|
app_path=$(ls -d dist/*.app build/dist/*.app build/*.app 2>/dev/null | head -n1 || true)
|
|
fi
|
|
if [ -n "$app_path" ] && [ -d "$app_path/Contents/Resources/lib/assets/branding/screenshots" ]; then
|
|
rm -rf "$app_path/Contents/Resources/lib/assets/branding/screenshots"
|
|
echo "Removed screenshots folder from .app bundle at $app_path"
|
|
fi
|
|
echo "Post-bdist_mac directory listing:"
|
|
echo "-- dist --"; ls -lah dist || true
|
|
echo "-- build --"; ls -lah build || true
|
|
|
|
- name: Build DMG (bdist_dmg)
|
|
shell: bash
|
|
run: |
|
|
source venv/bin/activate
|
|
python setup_cxfreeze.py bdist_dmg
|
|
echo "Post-bdist_dmg directory listing:"
|
|
echo "-- dist --"; ls -lah dist || true
|
|
echo "-- build --"; ls -lah build || true
|
|
|
|
- name: Package and prepare release artifacts (.app.zip and .dmg)
|
|
shell: bash
|
|
run: |
|
|
version="${{ steps.get_version.outputs.VERSION }}"
|
|
echo "Preparing artifacts for version: $version"
|
|
mkdir -p artifacts
|
|
|
|
# Find the .app bundle (preferring versioned name)
|
|
app_path=""
|
|
for cand in "dist/YTSage-v${version}.app" "build/dist/YTSage-v${version}.app" "build/YTSage-v${version}.app"; do
|
|
if [ -d "$cand" ]; then app_path="$cand"; break; fi
|
|
done
|
|
if [ -z "$app_path" ]; then
|
|
app_path=$(ls -d dist/*.app build/dist/*.app build/*.app 2>/dev/null | head -n1 || true)
|
|
fi
|
|
if [ -n "$app_path" ] && [ -d "$app_path" ]; then
|
|
app_base="$(basename "$app_path")"
|
|
app_parent="$(dirname "$app_path")"
|
|
# Ensure screenshots folder is not shipped
|
|
if [ -d "$app_path/Contents/Resources/lib/assets/branding/screenshots" ]; then
|
|
rm -rf "$app_path/Contents/Resources/lib/assets/branding/screenshots"
|
|
echo "Removed screenshots folder from .app bundle at $app_path"
|
|
fi
|
|
(cd "$app_parent" && zip -r "${GITHUB_WORKSPACE}/artifacts/YTSage-v${version}-${ARCH_SUFFIX}.app.zip" "$app_base")
|
|
echo "Created: artifacts/YTSage-v${version}-${ARCH_SUFFIX}.app.zip"
|
|
else
|
|
echo "Warning: .app bundle not found in dist/ or build/"
|
|
fi
|
|
|
|
# Try to find the generated DMG in dist or build
|
|
dmg_src=""
|
|
for cand in "dist/YTSage-v${version}.dmg"; do
|
|
if [ -f "$cand" ]; then dmg_src="$cand"; break; fi
|
|
done
|
|
if [ -z "$dmg_src" ]; then
|
|
dmg_src=$(ls dist/*.dmg build/*.dmg build/dist/*.dmg 2>/dev/null | head -n1 || true)
|
|
fi
|
|
|
|
if [ -n "$dmg_src" ] && [ -f "$dmg_src" ]; then
|
|
# Rename the DMG to a consistent name in artifacts
|
|
cp "$dmg_src" "artifacts/YTSage-v${version}-${ARCH_SUFFIX}.dmg"
|
|
echo "Copied DMG to artifacts from $dmg_src -> artifacts/YTSage-v${version}-${ARCH_SUFFIX}.dmg"
|
|
else
|
|
echo "Warning: No DMG found in dist/ or build/"
|
|
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 }}
|