Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
239 changes: 36 additions & 203 deletions .github/workflows/build-release.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Build and Release (Portable + Installer)
name: Build & Release (Portable EXE + MSI)

on:
workflow_dispatch:
Expand All @@ -10,247 +10,80 @@ permissions:

env:
RELEASE_DIR: releases
INSTALLER_SCRIPT: build/installer/StaTube.iss

jobs:
###############################################
# PORTABLE BUILD (onefile)
###############################################
build-portable:
name: Build Portable (onefile)
build:
runs-on: windows-latest

steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/checkout@v4

- name: Determine version from event
id: version
shell: bash
run: |
git fetch --tags
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
TAG=$(git describe --tags `git rev-list --tags --max-count=1`)
elif [[ "${{ github.event_name }}" == "release" ]]; then
TAG="${{ github.event.release.tag_name }}"
else
TAG="${{ github.ref_name }}"
fi
echo "TAG=$TAG" >> $GITHUB_OUTPUT

- name: Setup Python 3.11
uses: actions/setup-python@v4
- uses: actions/setup-python@v4
with:
python-version: "3.11"
cache: pip

- name: Install requirements + Nuitka plugins
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install "nuitka[plugins]"

- name: Build Portable EXE (Nuitka)
shell: cmd
run: |
python -m nuitka ^
--onefile ^
--windows-disable-console ^
--enable-plugin=pyside6 ^
--windows-icon-from-ico=assets/icon/StaTube.ico ^
--include-package=yt_dlp ^
--include-module=yt_dlp.utils ^
--include-package=nltk ^
--include-package=wordcloud ^
--include-package=utils ^
--include-package-data=wordcloud ^
--include-package-data=utils ^
--include-package=scrapetube ^
--nofollow-import-to=yt_dlp.extractor.lazy_extractors ^
--include-data-dir=assets=assets ^
--include-data-dir=UI=UI ^
--include-data-file=UI/Style.qss=UI/Style.qss ^
--include-data-file=Data/schema.sql=Data/schema.sql ^
--assume-yes-for-downloads ^
main.py

- name: Validate portable build output
shell: pwsh
run: |
if (!(Test-Path "./main.exe")) {
throw "Portable exe not found."
}

- name: Move and rename artifact
shell: pwsh
run: |
$version = "${{ steps.version.outputs.TAG }}"
New-Item -ItemType Directory -Force -Path $env:RELEASE_DIR | Out-Null
Move-Item "./main.exe" "./$env:RELEASE_DIR/StaTube-$version-portable.exe" -Force

# ---------- NEW: UPLOAD PORTABLE ARTIFACT ----------
- name: Upload portable artifact
uses: actions/upload-artifact@v4
with:
name: portable
path: releases/*.exe
# ----------------------------------------------------

###############################################
# INSTALLER BUILD (standalone)
###############################################
build-installer:
name: Build Installer (standalone)
runs-on: windows-latest

steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Determine version from event
id: version
shell: bash
run: |
git fetch --tags
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
TAG=$(git describe --tags `git.rev-list --tags --max-count=1`)
elif [[ "${{ github.event_name }}" == "release" ]]; then
TAG="${{ github.event.release.tag_name }}"
else
TAG="${{ github.ref_name }}"
fi
echo "TAG=$TAG" >> $GITHUB_OUTPUT

- name: Setup Python 3.11
uses: actions/setup-python@v4
with:
python-version: "3.11"
cache: pip

- name: Install requirements + Nuitka plugins
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install "nuitka[plugins]"
pip install pyinstaller cx_Freeze

# ---------- Extract metadata ----------
- name: Extract metadata
id: meta
shell: bash
run: |
python build/installer/extract_metadata.py main.py > meta.out
while IFS= read -r line; do echo "$line" >> $GITHUB_OUTPUT; done < meta.out
while IFS= read -r line; do
echo "$line" >> $GITHUB_ENV
done < meta.out

- name: Build Standalone Folder (Nuitka)
shell: cmd
# ---------- Portable EXE ----------
- name: Build portable EXE (PyInstaller)
run: |
python -m nuitka ^
--standalone ^
--output-dir=standalone_build ^
--windows-disable-console ^
--enable-plugin=pyside6 ^
--windows-icon-from-ico=assets/icon/StaTube.ico ^
--include-package=yt_dlp ^
--include-module=yt_dlp.utils ^
--include-package=nltk ^
--include-package=wordcloud ^
--include-package=utils ^
--include-package-data=wordcloud ^
--include-package-data=utils ^
--include-package=scrapetube ^
--nofollow-import-to=yt_dlp.extractor.lazy_extractors ^
--include-data-dir=assets=assets ^
--include-data-dir=UI=UI ^
--include-data-file=UI/Style.qss=UI/Style.qss ^
--include-data-file=Data/schema.sql=Data/schema.sql ^
--assume-yes-for-downloads ^
main.py
pyinstaller build/pyinstaller/StaTube.spec

- name: Validate standalone output
- name: Collect portable EXE
shell: pwsh
run: |
if (!(Test-Path "./standalone_build/main.dist")) {
throw "Standalone build folder missing!"
}
New-Item -ItemType Directory -Force $env:RELEASE_DIR | Out-Null
Move-Item dist/StaTube.exe "$env:RELEASE_DIR/${{ env.APP_NAME }}-${{ env.APP_VERSION }}-portable.exe"

- name: Create Installer Input Folder
shell: pwsh
# ---------- MSI Installer ----------
- name: Build MSI installer (cx_Freeze)
run: |
$version = "${{ steps.version.outputs.TAG }}"
New-Item -ItemType Directory -Force -Path $env:RELEASE_DIR | Out-Null
$target = "./$env:RELEASE_DIR/StaTube-$version-standalone"
if (Test-Path $target) { Remove-Item -Recurse -Force $target }
New-Item -ItemType Directory -Force -Path $target | Out-Null
Copy-Item -Recurse -Force "./standalone_build/main.dist/*" $target

- name: Install Inno Setup
shell: pwsh
run: choco install innosetup -y
python build/cxfreeze/setup.py bdist_msi

- name: Build Installer (ISCC)
- name: Collect MSI
shell: pwsh
run: |
$version = "${{ steps.version.outputs.TAG }}"
$name = "${{ steps.meta.outputs.APP_NAME }}"
$appver = "${{ steps.meta.outputs.APP_VERSION }}"
$pub = "${{ steps.meta.outputs.APP_PUBLISHER }}"
$desc = "${{ steps.meta.outputs.APP_DESCRIPTION }}"
Move-Item dist/*.msi "$env:RELEASE_DIR/${{ env.APP_NAME }}-${{ env.APP_VERSION }}-setup.msi"

& "C:\\Program Files (x86)\\Inno Setup 6\\ISCC.exe" `
/DMyAppName="$name" `
/DMyAppVersion="$appver" `
/DMyAppPublisher="$pub" `
/DMyAppDescription="$desc" `
/DMyAppTag="$version" `
/DSourceDir="${{ github.workspace }}\\releases\\StaTube-$version-standalone" `
/DOutputDir="${{ github.workspace }}\\releases" `
"${{ github.workspace }}\\build\\installer\\StaTube.iss"

- name: Validate installer output
shell: pwsh
run: |
$version = "${{ steps.version.outputs.TAG }}"
if (!(Test-Path "./$env:RELEASE_DIR/StaTube-$version-setup.exe")) {
throw "Installer not produced!"
}

# ---------- NEW: UPLOAD INSTALLER ARTIFACT ----------
- name: Upload installer artifact
uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v4
with:
name: installer
path: releases/*.exe
# ----------------------------------------------------
name: artifacts
path: releases/*

###############################################
# CREATE RELEASE
###############################################
create-release:
release:
runs-on: ubuntu-latest
needs: [build-portable, build-installer]
needs: build

steps:
- name: Download artifacts
uses: actions/download-artifact@v4
- uses: actions/download-artifact@v4
with:
path: artifacts
name: artifacts

- name: Create GitHub Release
- name: Publish release assets (append notes)
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ github.event.release.tag_name }}
name: ${{ github.event.release.tag_name }}
append_body: true
body: |
Automatic build for tag ${{ github.event.release.tag_name }}

**Included:**
- Portable EXE
- Installer EXE
- Source code
---
### Build Artifacts
- Portable single-file EXE
- MSI installer (supports upgrade & uninstall)
files: |
artifacts/**/*
*.exe
*.msi
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Loading
Loading