tg-ws-proxy/.github/workflows/build.yml
2026-05-08 20:42:31 +03:00

475 lines
15 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

name: Build & Release
on:
workflow_dispatch:
inputs:
make_release:
description: 'Create Github Release?'
type: boolean
required: true
default: false
version:
description: "Release version tag (e.g. v1.0.0)"
required: false
default: "v1.0.0"
permissions:
contents: write
jobs:
build-windows:
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: "3.11"
cache: "pip"
- name: Setup MSVC 14.40 toolset
uses: ilammy/msvc-dev-cmd@v1
with:
toolset: 14.40
- name: Install dependencies
run: pip install .
- name: Build PyInstaller bootloader from source
env:
PYINSTALLER_COMPILE_BOOTLOADER: "1"
run: |
pip download --no-binary pyinstaller --no-deps --no-cache-dir -d pyinstaller_src "pyinstaller==6.10.0"
pip install (Get-ChildItem pyinstaller_src\*.tar.gz).FullName
- name: Build EXE with PyInstaller
run: pyinstaller packaging/windows.spec --noconfirm
- name: Strip Rich PE header
shell: bash
run: |
python -c "
import struct, pathlib
exe = pathlib.Path('dist/TgWsProxy.exe')
data = bytearray(exe.read_bytes())
rich = data.find(b'Rich')
if rich == -1:
raise SystemExit('Rich header not found')
ck = struct.unpack_from('<I', data, rich + 4)[0]
dans = struct.pack('<I', 0x536E6144 ^ ck)
ds = data.find(dans)
if ds == -1:
raise SystemExit('DanS marker not found')
data[ds:rich + 8] = b'\x00' * (rich + 8 - ds)
exe.write_bytes(data)
print(f'Stripped Rich header: offset {ds}..{rich+8}')
"
- name: Rename artifact
run: mv dist/TgWsProxy.exe dist/TgWsProxy_windows.exe
- name: Upload artifact
uses: actions/upload-artifact@v7
with:
name: TgWsProxy
path: dist/TgWsProxy_windows.exe
build-win7:
runs-on: windows-latest
strategy:
matrix:
include:
- arch: x64
suffix: 64bit
- arch: x86
suffix: 32bit
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: "3.8"
architecture: ${{ matrix.arch }}
cache: "pip"
- name: Install dependencies & pyinstaller
run: pip install . "pyinstaller==5.13.2"
- name: Build EXE with PyInstaller
run: pyinstaller packaging/windows.spec --noconfirm
- name: Strip Rich PE header
shell: bash
run: |
python -c "
import struct, pathlib
exe = pathlib.Path('dist/TgWsProxy.exe')
data = bytearray(exe.read_bytes())
rich = data.find(b'Rich')
if rich == -1:
raise SystemExit('Rich header not found')
ck = struct.unpack_from('<I', data, rich + 4)[0]
dans = struct.pack('<I', 0x536E6144 ^ ck)
ds = data.find(dans)
if ds == -1:
raise SystemExit('DanS marker not found')
data[ds:rich + 8] = b'\x00' * (rich + 8 - ds)
exe.write_bytes(data)
print(f'Stripped Rich header: offset {ds}..{rich+8}')
"
- name: Rename artifact
run: mv dist/TgWsProxy.exe dist/TgWsProxy_windows_7_${{ matrix.suffix }}.exe
- name: Upload artifact
uses: actions/upload-artifact@v7
with:
name: TgWsProxy-win7-${{ matrix.suffix }}
path: dist/TgWsProxy_windows_7_${{ matrix.suffix }}.exe
build-macos:
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install universal2 Python
run: |
set -euo pipefail
curl -LO https://www.python.org/ftp/python/3.12.10/python-3.12.10-macos11.pkg
sudo installer -pkg python-3.12.10-macos11.pkg -target /
echo "/Library/Frameworks/Python.framework/Versions/3.12/bin" >> "$GITHUB_PATH"
- name: Install dependencies
run: |
set -euo pipefail
python3.12 -m pip install --upgrade pip setuptools wheel
python3.12 -m pip install delocate==0.13.0
mkdir -p wheelhouse/arm64 wheelhouse/x86_64 wheelhouse/universal2
python3.12 -m pip download \
--only-binary=:all: \
--platform macosx_11_0_arm64 \
--python-version 3.12 \
--implementation cp \
-d wheelhouse/arm64 \
'cffi>=2.0.0' \
Pillow==12.1.0 \
psutil==7.0.0
python3.12 -m pip download \
--only-binary=:all: \
--platform macosx_10_13_x86_64 \
--python-version 3.12 \
--implementation cp \
-d wheelhouse/x86_64 \
'cffi>=2.0.0' \
Pillow==12.1.0
python3.12 -m pip download \
--only-binary=:all: \
--platform macosx_10_9_x86_64 \
--python-version 3.12 \
--implementation cp \
-d wheelhouse/x86_64 \
psutil==7.0.0
delocate-merge \
wheelhouse/arm64/cffi-*.whl \
wheelhouse/x86_64/cffi-*.whl \
-w wheelhouse/universal2
delocate-merge \
wheelhouse/arm64/pillow-12.1.0-*.whl \
wheelhouse/x86_64/pillow-12.1.0-*.whl \
-w wheelhouse/universal2
delocate-merge \
wheelhouse/arm64/psutil-7.0.0-*.whl \
wheelhouse/x86_64/psutil-7.0.0-*.whl \
-w wheelhouse/universal2
python3.12 -m pip install --no-deps wheelhouse/universal2/*.whl
python3.12 -m pip install .
python3.12 -m pip install pyinstaller==6.13.0
- name: Create macOS icon from ICO
run: |
set -euo pipefail
python3.12 - <<'PY'
from PIL import Image
image = Image.open('icon.ico')
image = image.resize((1024, 1024), Image.LANCZOS)
image.save('icon_1024.png', 'PNG')
PY
mkdir -p icon.iconset
sips -z 16 16 icon_1024.png --out icon.iconset/icon_16x16.png
sips -z 32 32 icon_1024.png --out icon.iconset/icon_16x16@2x.png
sips -z 32 32 icon_1024.png --out icon.iconset/icon_32x32.png
sips -z 64 64 icon_1024.png --out icon.iconset/icon_32x32@2x.png
sips -z 128 128 icon_1024.png --out icon.iconset/icon_128x128.png
sips -z 256 256 icon_1024.png --out icon.iconset/icon_128x128@2x.png
sips -z 256 256 icon_1024.png --out icon.iconset/icon_256x256.png
sips -z 512 512 icon_1024.png --out icon.iconset/icon_256x256@2x.png
sips -z 512 512 icon_1024.png --out icon.iconset/icon_512x512.png
sips -z 1024 1024 icon_1024.png --out icon.iconset/icon_512x512@2x.png
iconutil -c icns icon.iconset -o icon.icns
rm -rf icon.iconset icon_1024.png
- name: Build app with PyInstaller
run: python3.12 -m PyInstaller packaging/macos.spec --noconfirm
- name: Validate universal2 app bundle
run: |
set -euo pipefail
found=0
while IFS= read -r -d '' file; do
if file "$file" | grep -q "Mach-O"; then
found=1
archs="$(lipo -archs "$file" 2>/dev/null || true)"
case "$archs" in
*arm64*x86_64*|*x86_64*arm64*) ;;
*)
echo "Missing universal2 slices in $file: ${archs:-unknown}" >&2
exit 1
;;
esac
fi
done < <(find "dist/TG WS Proxy.app" -type f -print0)
if [ "$found" -eq 0 ]; then
echo "No Mach-O files found in app bundle" >&2
exit 1
fi
- name: Create DMG
run: |
set -euo pipefail
APP_NAME="TG WS Proxy"
DMG_TEMP="dist/dmg_temp"
rm -rf "$DMG_TEMP"
mkdir -p "$DMG_TEMP"
cp -R "dist/${APP_NAME}.app" "$DMG_TEMP/"
ln -s /Applications "$DMG_TEMP/Applications"
hdiutil create \
-volname "$APP_NAME" \
-srcfolder "$DMG_TEMP" \
-ov \
-format UDZO \
"dist/TgWsProxy_macos_universal.dmg"
rm -rf "$DMG_TEMP"
- name: Upload artifact
uses: actions/upload-artifact@v7
with:
name: TgWsProxy-macOS
path: dist/TgWsProxy_macos_universal.dmg
build-linux:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
python3-venv \
python3-dev \
python3-gi \
gir1.2-ayatanaappindicator3-0.1 \
python3-tk
- name: Create venv with system site-packages
run: python3 -m venv --system-site-packages .venv
- name: Install dependencies
run: |
.venv/bin/pip install --upgrade pip
.venv/bin/pip install .
.venv/bin/pip install "pyinstaller==6.13.0"
- name: Build binary with PyInstaller
run: .venv/bin/pyinstaller packaging/linux.spec --noconfirm
- name: Rename binary artifact
run: mv dist/TgWsProxy dist/TgWsProxy_linux_amd64
- name: Create .deb package
run: |
set -euo pipefail
VERSION="${{ github.event.inputs.version }}"
VERSION="${VERSION#v}"
PKG_ROOT="pkg"
rm -rf "$PKG_ROOT"
mkdir -p \
"$PKG_ROOT/DEBIAN" \
"$PKG_ROOT/usr/bin" \
"$PKG_ROOT/usr/share/applications" \
"$PKG_ROOT/usr/share/icons/hicolor/256x256/apps"
install -m 755 dist/TgWsProxy_linux_amd64 "$PKG_ROOT/usr/bin/tg-ws-proxy"
.venv/bin/python - <<PY
from PIL import Image
Image.open("icon.ico").save(
"${PKG_ROOT}/usr/share/icons/hicolor/256x256/apps/tg-ws-proxy.png",
"PNG",
)
PY
cat > "$PKG_ROOT/usr/share/applications/tg-ws-proxy.desktop" <<EOF
[Desktop Entry]
Type=Application
Name=TG WS Proxy
GenericName=Telegram Proxy
Comment=Telegram Desktop WebSocket Bridge Proxy
Exec=tg-ws-proxy
Icon=tg-ws-proxy
Terminal=false
Categories=Network;
StartupNotify=true
Keywords=telegram;proxy;websocket;
EOF
cat > "$PKG_ROOT/DEBIAN/control" <<EOF
Package: tg-ws-proxy
Version: ${VERSION}
Section: net
Priority: optional
Architecture: amd64
Maintainer: Flowseal
Depends: libgtk-3-0, libayatana-appindicator3-1, python3-tk
Description: Telegram Desktop WebSocket Bridge Proxy
MTProto/WebSocket bridge proxy for Telegram Desktop with tray UI.
EOF
dpkg-deb --build --root-owner-group \
"$PKG_ROOT" \
"dist/TgWsProxy_linux_amd64.deb"
- name: Create .rpm package with fpm
run: |
set -euo pipefail
VERSION="${{ github.event.inputs.version }}"
VERSION="${VERSION#v}"
sudo gem install fpm -v 1.17.0
mkdir -p rpm_package/usr/bin
mkdir -p rpm_package/usr/share/applications
mkdir -p rpm_package/usr/share/icons/hicolor/256x256/apps
cp dist/TgWsProxy_linux_amd64 rpm_package/usr/bin/tg-ws-proxy
chmod 755 rpm_package/usr/bin/tg-ws-proxy
.venv/bin/python - <<PY
from PIL import Image
Image.open("icon.ico").save(
"rpm_package/usr/share/icons/hicolor/256x256/apps/tg-ws-proxy.png",
"PNG",
)
PY
cat > rpm_package/usr/share/applications/tg-ws-proxy.desktop <<EOF
[Desktop Entry]
Type=Application
Name=TG WS Proxy
GenericName=Telegram Proxy
Comment=Telegram Desktop WebSocket Bridge Proxy
Exec=tg-ws-proxy
Icon=tg-ws-proxy
Terminal=false
Categories=Network;
StartupNotify=true
Keywords=telegram;proxy;websocket;
EOF
cat > post_install.sh <<EOF
#!/bin/bash
if [ -x /usr/bin/update-desktop-database ]; then
/usr/bin/update-desktop-database &> /dev/null || :
fi
if [ -x /usr/bin/gtk-update-icon-cache ]; then
/usr/bin/gtk-update-icon-cache -q /usr/share/icons/hicolor &> /dev/null || :
fi
EOF
chmod +x post_install.sh
fpm -s dir \
-t rpm \
-n tg-ws-proxy \
-v ${VERSION} \
--iteration 1 \
--architecture x86_64 \
--license "MIT" \
--vendor "Flowseal" \
--maintainer "Flowseal" \
--url "https://github.com/Flowseal/tg-ws-proxy" \
--description "MTProto/WebSocket bridge proxy for Telegram Desktop with tray UI." \
--depends "libgtk-3.so.0()(64bit)" \
--depends "libayatana-appindicator3.so.1()(64bit)" \
--depends "python3-tkinter" \
--after-install post_install.sh \
--after-remove post_install.sh \
-C rpm_package \
.
mv tg-ws-proxy-${VERSION}-1.x86_64.rpm dist/TgWsProxy_linux_amd64.rpm
- name: Upload artifact
uses: actions/upload-artifact@v7
with:
name: TgWsProxy-linux
path: |
dist/TgWsProxy_linux_amd64
dist/TgWsProxy_linux_amd64.deb
dist/TgWsProxy_linux_amd64.rpm
release:
needs: [build-windows, build-win7, build-macos, build-linux]
runs-on: ubuntu-latest
if: ${{ github.event.inputs.make_release == 'true' }}
steps:
- uses: actions/download-artifact@v8
with:
pattern: TgWsProxy*
path: dist
merge-multiple: true
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.event.inputs.version }}
name: "TG WS Proxy ${{ github.event.inputs.version }}"
body: |
##
### [❤️ Поддержать развитие проекта](https://github.com/Flowseal/tg-ws-proxy/blob/main/docs/Funding.md)
> [!TIP]
> Не можете скачать?
> Добавьте `185.199.109.133 release-assets.githubusercontent.com` в hosts или воспользуйтесь зеркалом: https://sourceforge.net/projects/tg-ws-proxy.mirror/files/
files: |
dist/TgWsProxy_windows.exe
dist/TgWsProxy_windows_7_64bit.exe
dist/TgWsProxy_windows_7_32bit.exe
dist/TgWsProxy_macos_universal.dmg
dist/TgWsProxy_linux_amd64
dist/TgWsProxy_linux_amd64.deb
dist/TgWsProxy_linux_amd64.rpm
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}