name: Release
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+' # stable: v1.0.0
- 'v[0-9]+.[0-9]+.[0-9]+-alpha*' # alpha: v1.0.0-alpha1
- 'v[0-9]+.[0-9]+.[0-9]+-test*' # tester: v1.0.0-test1
jobs:
# ===========================================================================
# Windows Build
# ===========================================================================
build-windows:
runs-on: windows
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup MSVC
uses: ilammy/msvc-dev-cmd@v1
with:
arch: x64
- name: Extract version info
shell: cmd
run: |
setlocal enabledelayedexpansion
set "TAG=%GITHUB_REF_NAME%"
set "VERSION=!TAG:~1!"
set "CHANNEL=stable"
echo !TAG! | findstr /C:"-alpha" >nul && set "CHANNEL=alpha"
echo !TAG! | findstr /C:"-test" >nul && set "CHANNEL=tester"
REM Extract clean version (remove -alpha* or -test* suffix)
set "CLEAN_VERSION=!VERSION!"
for /f "tokens=1 delims=-" %%a in ("!VERSION!") do set "CLEAN_VERSION=%%a"
echo VERSION=!VERSION!>> %GITHUB_ENV%
echo CLEAN_VERSION=!CLEAN_VERSION!>> %GITHUB_ENV%
echo CHANNEL=!CHANNEL!>> %GITHUB_ENV%
echo Building version: !VERSION! for channel: !CHANNEL!
- name: Build Release
shell: cmd
run: |
set PATH=C:\Qt\6.10.1\msvc2022_64\bin;C:\Qt\Tools\QtCreator\bin\jom;%PATH%
if not exist build mkdir build
cd build
echo === Running qmake ===
qmake.exe ..\XPlor.pro -spec win32-msvc "CONFIG+=release"
if errorlevel 1 exit /b 1
echo === Building with jom ===
jom.exe -j %NUMBER_OF_PROCESSORS%
if errorlevel 1 exit /b 1
- name: Deploy Qt Libraries
shell: cmd
run: |
set PATH=C:\Qt\6.10.1\msvc2022_64\bin;%PATH%
echo === windeployqt for app ===
cd build\app\release
windeployqt6.exe --release --no-translations app.exe
if errorlevel 1 exit /b 1
cd ..\..\..
echo === windeployqt for cli ===
cd build\tools\cli\release
windeployqt6.exe --release --no-translations cli.exe
- name: Package for Installer
shell: cmd
run: |
set GUI_DATA=installer\packages\com.xplor.gui\data
set CLI_DATA=installer\packages\com.xplor.cli\data
REM Clean and create directories
if exist "%GUI_DATA%" rmdir /s /q "%GUI_DATA%"
if exist "%CLI_DATA%" rmdir /s /q "%CLI_DATA%"
mkdir "%GUI_DATA%"
mkdir "%CLI_DATA%\cli"
REM Copy GUI files
xcopy /s /e /y /q "build\app\release\*" "%GUI_DATA%\" >nul
if exist "%GUI_DATA%\definitions" rmdir /s /q "%GUI_DATA%\definitions"
if exist "%GUI_DATA%\scripts" rmdir /s /q "%GUI_DATA%\scripts"
if exist "%GUI_DATA%\app.exe" ren "%GUI_DATA%\app.exe" "XPlor.exe"
REM Copy CLI files
xcopy /s /e /y /q "build\tools\cli\release\*" "%CLI_DATA%\cli\" >nul
if exist "%CLI_DATA%\cli\cli.exe" ren "%CLI_DATA%\cli\cli.exe" "xplor-cli.exe"
echo Packaging complete
- name: Package Definitions and Docs
shell: cmd
run: |
setlocal enabledelayedexpansion
REM Package each definition set
for %%D in (cod volition deadrising asura fmod thqa wii) do (
set "DEF_DATA=installer\packages\com.xplor.definitions.%%D\data"
if exist "!DEF_DATA!" rmdir /s /q "!DEF_DATA!"
mkdir "!DEF_DATA!\definitions\%%D" 2>nul
if exist "definitions\%%D" (
xcopy /s /e /y /q "definitions\%%D\*" "!DEF_DATA!\definitions\%%D\" >nul
)
)
REM Package docs
set DOCS_DATA=installer\packages\com.xplor.docs\data
if exist "%DOCS_DATA%" rmdir /s /q "%DOCS_DATA%"
mkdir "%DOCS_DATA%\docs"
if exist "docs\xscript-guide.pdf" copy /y "docs\xscript-guide.pdf" "%DOCS_DATA%\docs\" >nul
if exist "docs\xscript-guide.md" copy /y "docs\xscript-guide.md" "%DOCS_DATA%\docs\" >nul
REM Package scripts
set SCRIPTS_DATA=installer\packages\com.xplor.scripts\data
if exist "%SCRIPTS_DATA%" rmdir /s /q "%SCRIPTS_DATA%"
mkdir "%SCRIPTS_DATA%\scripts"
if exist "scripts" xcopy /s /e /y /q "scripts\*" "%SCRIPTS_DATA%\scripts\" >nul
echo Definitions and docs packaged
- name: Update Package Versions
shell: cmd
run: |
setlocal enabledelayedexpansion
set "VERSION=%CLEAN_VERSION%"
set "CHANNEL=%CHANNEL%"
REM Get today's date in YYYY-MM-DD format
for /f "tokens=2 delims==" %%I in ('wmic os get localdatetime /value') do set "DT=%%I"
set "TODAY=!DT:~0,4!-!DT:~4,2!-!DT:~6,2!"
echo Updating to version !VERSION! for channel !CHANNEL! on !TODAY!
REM Update package.xml files using PowerShell for regex
for /r installer\packages %%f in (package.xml) do (
if exist "%%f" (
powershell -Command "(Get-Content '%%f') -replace '.*', '%VERSION%' -replace '.*', '%TODAY%' | Set-Content '%%f'"
)
)
REM Update config.xml
powershell -Command "(Get-Content 'installer\config\config.xml') -replace '.*', '%VERSION%' -replace 'repository/[^<\"]*', 'repository/%CHANNEL%' | Set-Content 'installer\config\config.xml'"
echo Updated versions to !VERSION! for channel !CHANNEL!
- name: Generate Repository
shell: cmd
run: |
set PATH=C:\Qt\Tools\QtInstallerFramework\4.8\bin;%PATH%
if exist repository rmdir /s /q repository
mkdir repository
repogen.exe --update-new-components -p installer\packages repository
if errorlevel 1 exit /b 1
echo Repository generated
- name: Create Offline Installer
shell: cmd
run: |
set PATH=C:\Qt\Tools\QtInstallerFramework\4.8\bin;%PATH%
binarycreator.exe --offline-only -c installer\config\config.xml -p installer\packages "XPlor-%VERSION%-Windows-Setup.exe"
if errorlevel 1 exit /b 1
echo Created: XPlor-%VERSION%-Windows-Setup.exe
- name: Create Online Installer
shell: cmd
run: |
set PATH=C:\Qt\Tools\QtInstallerFramework\4.8\bin;%PATH%
binarycreator.exe --online-only -c installer\config\config.xml -p installer\packages "XPlor-%VERSION%-Windows-Online.exe"
if errorlevel 1 exit /b 1
echo Created: XPlor-%VERSION%-Windows-Online.exe
- name: Deploy to Repository
shell: cmd
run: |
set REPO_PATH=P:\repository\%CHANNEL%
echo Deploying to %REPO_PATH%
if not exist "%REPO_PATH%" mkdir "%REPO_PATH%"
REM Copy repository contents
xcopy /s /e /y /q "repository\*" "%REPO_PATH%\" >nul
echo Repository updated at %REPO_PATH%
- name: Upload Installers
uses: actions/upload-artifact@v4
with:
name: windows-installers
path: |
XPlor-*-Windows-Setup.exe
XPlor-*-Windows-Online.exe
retention-days: 90
# ===========================================================================
# macOS Build
# ===========================================================================
build-macos:
runs-on: macos
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Extract version info
shell: bash
run: |
TAG="${GITHUB_REF_NAME}"
VERSION="${TAG#v}"
if [[ "$TAG" == *"-alpha"* ]]; then
CHANNEL="alpha"
elif [[ "$TAG" == *"-test"* ]]; then
CHANNEL="tester"
else
CHANNEL="stable"
fi
CLEAN_VERSION=$(echo "$VERSION" | sed 's/-alpha.*//' | sed 's/-test.*//')
echo "VERSION=$VERSION" >> $GITHUB_ENV
echo "CLEAN_VERSION=$CLEAN_VERSION" >> $GITHUB_ENV
echo "CHANNEL=$CHANNEL" >> $GITHUB_ENV
- name: Build Release
shell: bash
run: |
# Find Qt
for QT_PATH in ~/Qt/6.10.1/macos ~/Qt/6.9.0/macos ~/Qt/6.8.0/macos /opt/homebrew/opt/qt@6; do
if [ -f "$QT_PATH/bin/qmake" ]; then
echo "Found Qt at: $QT_PATH"
export PATH="$QT_PATH/bin:$PATH"
echo "QT_PATH=$QT_PATH" >> $GITHUB_ENV
break
fi
done
which qmake || { echo "ERROR: qmake not found"; exit 1; }
mkdir -p build
cd build
qmake ../XPlor.pro -spec macx-clang "CONFIG+=release"
make -j$(sysctl -n hw.ncpu)
- name: Deploy Qt Libraries
shell: bash
run: |
export PATH="$QT_PATH/bin:$PATH"
cd build/app
if [ -d "XPlor.app" ] || [ -d "app.app" ]; then
APP_NAME=$(ls -d *.app | head -1)
macdeployqt "$APP_NAME" -verbose=1
# Rename if needed
if [ "$APP_NAME" = "app.app" ]; then
mv app.app XPlor.app
fi
fi
- name: Package for Installer
shell: bash
run: |
set -x # Debug: show commands
echo "=== Starting Package for Installer ==="
echo "Current directory: $(pwd)"
echo "Build directory contents:"
ls -la build/app/ || echo "build/app not found"
GUI_DATA="installer/packages/com.xplor.gui/data"
CLI_DATA="installer/packages/com.xplor.cli/data"
rm -rf "$GUI_DATA" "$CLI_DATA"
mkdir -p "$GUI_DATA" "$CLI_DATA/cli"
# Copy app bundle
if [ -d "build/app/XPlor.app" ]; then
echo "Copying XPlor.app..."
cp -R "build/app/XPlor.app" "$GUI_DATA/"
elif [ -d "build/app/app.app" ]; then
echo "Copying app.app as XPlor.app..."
cp -R "build/app/app.app" "$GUI_DATA/XPlor.app"
else
echo "WARNING: No app bundle found"
ls -la build/app/ || true
fi
# Copy CLI
if [ -f "build/tools/cli/cli" ]; then
cp "build/tools/cli/cli" "$CLI_DATA/cli/xplor-cli"
chmod +x "$CLI_DATA/cli/xplor-cli"
else
echo "WARNING: CLI binary not found"
fi
# Package definitions (use find to avoid glob issues)
for def in cod volition deadrising asura fmod thqa wii; do
DEF_DATA="installer/packages/com.xplor.definitions.$def/data"
rm -rf "$DEF_DATA"
mkdir -p "$DEF_DATA/definitions/$def"
if [ -d "definitions/$def" ] && [ "$(ls -A definitions/$def 2>/dev/null)" ]; then
cp -R "definitions/$def/"* "$DEF_DATA/definitions/$def/" || true
fi
done
# Package docs
DOCS_DATA="installer/packages/com.xplor.docs/data"
rm -rf "$DOCS_DATA"
mkdir -p "$DOCS_DATA/docs"
[ -f "docs/xscript-guide.pdf" ] && cp "docs/xscript-guide.pdf" "$DOCS_DATA/docs/" || true
[ -f "docs/xscript-guide.md" ] && cp "docs/xscript-guide.md" "$DOCS_DATA/docs/" || true
# Package scripts (may not exist in repo)
SCRIPTS_DATA="installer/packages/com.xplor.scripts/data"
rm -rf "$SCRIPTS_DATA"
mkdir -p "$SCRIPTS_DATA/scripts"
if [ -d "scripts" ] && [ "$(ls -A scripts 2>/dev/null)" ]; then
cp -R scripts/* "$SCRIPTS_DATA/scripts/" || true
fi
echo "=== Package for Installer complete ==="
- name: Update Package Versions
shell: bash
run: |
VERSION="${{ env.CLEAN_VERSION }}"
CHANNEL="${{ env.CHANNEL }}"
TODAY=$(date +%Y-%m-%d)
# Update package.xml files
find installer/packages -name "package.xml" -exec sed -i '' \
-e "s|.*|$VERSION|" \
-e "s|.*|$TODAY|" {} \;
# Update config.xml
sed -i '' \
-e "s|.*|$VERSION|" \
-e "s|repository/[^<\"]*|repository/$CHANNEL|" \
installer/config/config.xml
- name: Generate Repository and Installers
shell: bash
run: |
# Find Qt IFW
for IFW_PATH in ~/Qt/Tools/QtInstallerFramework/4.8/bin ~/Qt/Tools/QtInstallerFramework/4.7/bin /opt/homebrew/opt/qt-installer-framework/bin; do
if [ -f "$IFW_PATH/repogen" ]; then
echo "Found Qt IFW at: $IFW_PATH"
export PATH="$IFW_PATH:$PATH"
break
fi
done
which repogen || { echo "ERROR: Qt IFW not found"; exit 1; }
# Generate repository
rm -rf repository
mkdir repository
repogen --update-new-components -p installer/packages repository
# Create offline installer
binarycreator --offline-only -c installer/config/config.xml -p installer/packages "XPlor-${VERSION}-macOS-Setup"
# Create online installer
binarycreator --online-only -c installer/config/config.xml -p installer/packages "XPlor-${VERSION}-macOS-Online"
# Create DMG for offline installer
if [ -d "XPlor-${VERSION}-macOS-Setup.app" ]; then
hdiutil create -volname "XPlor Installer" -srcfolder "XPlor-${VERSION}-macOS-Setup.app" -ov -format UDZO "XPlor-${VERSION}-macOS-Setup.dmg"
fi
if [ -d "XPlor-${VERSION}-macOS-Online.app" ]; then
hdiutil create -volname "XPlor Online Installer" -srcfolder "XPlor-${VERSION}-macOS-Online.app" -ov -format UDZO "XPlor-${VERSION}-macOS-Online.dmg"
fi
ls -la XPlor-*
- name: Upload Installers
uses: actions/upload-artifact@v4
with:
name: macos-installers
path: |
XPlor-*-macOS-Setup.dmg
XPlor-*-macOS-Online.dmg
XPlor-*-macOS-Setup
XPlor-*-macOS-Online
retention-days: 90
- name: Upload Repository
uses: actions/upload-artifact@v4
with:
name: macos-repository
path: repository/
retention-days: 90
# ===========================================================================
# Linux Build
# ===========================================================================
build-linux:
runs-on: ubuntu
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Dependencies
shell: bash
run: |
if command -v sudo &> /dev/null; then
SUDO="sudo"
else
SUDO=""
fi
$SUDO apt-get update || true
$SUDO apt-get install -y build-essential libgl1-mesa-dev zlib1g-dev
- name: Extract version info
shell: bash
run: |
TAG="${GITHUB_REF_NAME}"
VERSION="${TAG#v}"
if [[ "$TAG" == *"-alpha"* ]]; then
CHANNEL="alpha"
elif [[ "$TAG" == *"-test"* ]]; then
CHANNEL="tester"
else
CHANNEL="stable"
fi
CLEAN_VERSION=$(echo "$VERSION" | sed 's/-alpha.*//' | sed 's/-test.*//')
echo "VERSION=$VERSION" >> $GITHUB_ENV
echo "CLEAN_VERSION=$CLEAN_VERSION" >> $GITHUB_ENV
echo "CHANNEL=$CHANNEL" >> $GITHUB_ENV
- name: Build Release
shell: bash
run: |
# Find Qt
for QT_PATH in ~/Qt/6.10.1/gcc_64 ~/Qt/6.9.0/gcc_64 ~/Qt/6.8.0/gcc_64 /opt/Qt/6.10.1/gcc_64 /usr/lib/qt6; do
if [ -f "$QT_PATH/bin/qmake" ]; then
echo "Found Qt at: $QT_PATH"
export PATH="$QT_PATH/bin:$PATH"
export LD_LIBRARY_PATH="$QT_PATH/lib:$LD_LIBRARY_PATH"
echo "QT_PATH=$QT_PATH" >> $GITHUB_ENV
break
fi
done
which qmake || { echo "ERROR: qmake not found"; exit 1; }
mkdir -p build
cd build
qmake ../XPlor.pro -spec linux-g++ "CONFIG+=release"
make -j$(nproc)
- name: Package for Installer
shell: bash
run: |
set -x # Debug: show commands
echo "=== Starting Package for Installer (Linux) ==="
GUI_DATA="installer/packages/com.xplor.gui/data"
CLI_DATA="installer/packages/com.xplor.cli/data"
rm -rf "$GUI_DATA" "$CLI_DATA"
mkdir -p "$GUI_DATA" "$CLI_DATA/cli"
# Copy GUI binary and create wrapper script
if [ -f "build/app/app" ]; then
cp "build/app/app" "$GUI_DATA/XPlor"
chmod +x "$GUI_DATA/XPlor"
else
echo "WARNING: GUI binary not found"
fi
# Copy CLI
if [ -f "build/tools/cli/cli" ]; then
cp "build/tools/cli/cli" "$CLI_DATA/cli/xplor-cli"
chmod +x "$CLI_DATA/cli/xplor-cli"
else
echo "WARNING: CLI binary not found"
fi
# Copy Qt libraries (basic deployment)
if [ -n "$QT_PATH" ] && [ -d "$QT_PATH/lib" ]; then
mkdir -p "$GUI_DATA/lib"
for lib in Core Gui Widgets Network Multimedia Svg; do
[ -f "$QT_PATH/lib/libQt6${lib}.so.6" ] && cp "$QT_PATH/lib/libQt6${lib}.so.6" "$GUI_DATA/lib/"
done
# Copy plugins
mkdir -p "$GUI_DATA/plugins/platforms"
[ -d "$QT_PATH/plugins/platforms" ] && cp "$QT_PATH/plugins/platforms/"*.so "$GUI_DATA/plugins/platforms/" 2>/dev/null || true
fi
# Package definitions (check for non-empty directories)
for def in cod volition deadrising asura fmod thqa wii; do
DEF_DATA="installer/packages/com.xplor.definitions.$def/data"
rm -rf "$DEF_DATA"
mkdir -p "$DEF_DATA/definitions/$def"
if [ -d "definitions/$def" ] && [ "$(ls -A definitions/$def 2>/dev/null)" ]; then
cp -R "definitions/$def/"* "$DEF_DATA/definitions/$def/" || true
fi
done
# Package docs
DOCS_DATA="installer/packages/com.xplor.docs/data"
rm -rf "$DOCS_DATA"
mkdir -p "$DOCS_DATA/docs"
[ -f "docs/xscript-guide.pdf" ] && cp "docs/xscript-guide.pdf" "$DOCS_DATA/docs/" || true
[ -f "docs/xscript-guide.md" ] && cp "docs/xscript-guide.md" "$DOCS_DATA/docs/" || true
# Package scripts (may not exist in repo)
SCRIPTS_DATA="installer/packages/com.xplor.scripts/data"
rm -rf "$SCRIPTS_DATA"
mkdir -p "$SCRIPTS_DATA/scripts"
if [ -d "scripts" ] && [ "$(ls -A scripts 2>/dev/null)" ]; then
cp -R scripts/* "$SCRIPTS_DATA/scripts/" || true
fi
echo "=== Package for Installer complete ==="
- name: Update Package Versions
shell: bash
run: |
VERSION="${{ env.CLEAN_VERSION }}"
CHANNEL="${{ env.CHANNEL }}"
TODAY=$(date +%Y-%m-%d)
# Update package.xml files
find installer/packages -name "package.xml" -exec sed -i \
-e "s|.*|$VERSION|" \
-e "s|.*|$TODAY|" {} \;
# Update config.xml
sed -i \
-e "s|.*|$VERSION|" \
-e "s|repository/[^<\"]*|repository/$CHANNEL|" \
installer/config/config.xml
- name: Generate Repository and Installers
shell: bash
run: |
# Find Qt IFW
for IFW_PATH in ~/Qt/Tools/QtInstallerFramework/4.8/bin ~/Qt/Tools/QtInstallerFramework/4.7/bin /opt/Qt/Tools/QtInstallerFramework/4.8/bin; do
if [ -f "$IFW_PATH/repogen" ]; then
echo "Found Qt IFW at: $IFW_PATH"
export PATH="$IFW_PATH:$PATH"
break
fi
done
which repogen || { echo "ERROR: Qt IFW not found"; exit 1; }
# Generate repository
rm -rf repository
mkdir repository
repogen --update-new-components -p installer/packages repository
# Create offline installer (.run)
binarycreator --offline-only -c installer/config/config.xml -p installer/packages "XPlor-${VERSION}-Linux-Setup.run"
# Create online installer (.run)
binarycreator --online-only -c installer/config/config.xml -p installer/packages "XPlor-${VERSION}-Linux-Online.run"
chmod +x XPlor-*.run
ls -la XPlor-*
- name: Upload Installers
uses: actions/upload-artifact@v4
with:
name: linux-installers
path: |
XPlor-*-Linux-Setup.run
XPlor-*-Linux-Online.run
retention-days: 90
- name: Upload Repository
uses: actions/upload-artifact@v4
with:
name: linux-repository
path: repository/
retention-days: 90
# ===========================================================================
# Deploy - Merge repositories and create release
# ===========================================================================
deploy:
runs-on: windows
needs: [build-windows, build-macos, build-linux]
steps:
- name: Extract version info
shell: cmd
run: |
setlocal enabledelayedexpansion
set "TAG=%GITHUB_REF_NAME%"
set "VERSION=!TAG:~1!"
set "CHANNEL=stable"
echo !TAG! | findstr /C:"-alpha" >nul && set "CHANNEL=alpha"
echo !TAG! | findstr /C:"-test" >nul && set "CHANNEL=tester"
echo VERSION=!VERSION!>> %GITHUB_ENV%
echo CHANNEL=!CHANNEL!>> %GITHUB_ENV%
- name: Download all installers
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Download macOS repository
uses: actions/download-artifact@v4
with:
name: macos-repository
path: repo-macos
- name: Download Linux repository
uses: actions/download-artifact@v4
with:
name: linux-repository
path: repo-linux
- name: Merge repositories
shell: cmd
run: |
setlocal enabledelayedexpansion
set "CHANNEL=%CHANNEL%"
set "REPO_PATH=P:\repository\!CHANNEL!"
echo Deploying to: !REPO_PATH!
REM Ensure directory exists
if not exist "!REPO_PATH!" mkdir "!REPO_PATH!"
REM The Windows build already deployed its repository
REM Now merge macOS and Linux platform-specific packages
REM Copy macOS repository components
if exist "repo-macos" (
xcopy /s /e /y /q "repo-macos\*" "!REPO_PATH!\" >nul
echo Merged macOS repository
)
REM Copy Linux repository components
if exist "repo-linux" (
xcopy /s /e /y /q "repo-linux\*" "!REPO_PATH!\" >nul
echo Merged Linux repository
)
echo Repository deployed to !REPO_PATH!
- name: Collect all installers
shell: cmd
run: |
REM Create release directory
if not exist release mkdir release
REM Copy all installers from artifacts
for /r artifacts %%f in (XPlor-*.exe XPlor-*.dmg XPlor-*.run) do (
if exist "%%f" (
copy /y "%%f" release\ >nul
echo Found: %%~nxf
)
)
dir release\
- name: Create Gitea Release
uses: softprops/action-gh-release@v2
with:
files: release/*
generate_release_notes: true
prerelease: ${{ contains(github.ref_name, 'alpha') || contains(github.ref_name, 'test') }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}