mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-05-13 17:46:02 +00:00
In the CodeQL workflow, add Node.js setup and a frontend build step for the Go matrix so vite emits web/dist before CodeQL's Go autobuild (the Go binary uses //go:embed all:dist and web/dist is .gitignored). In the release workflow, remove the separate Go analyze job (gofmt, go vet, staticcheck, tests) and drop its dependency from build jobs to simplify the release pipeline.
278 lines
10 KiB
YAML
278 lines
10 KiB
YAML
name: Release 3X-UI
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
push:
|
|
branches:
|
|
- "**"
|
|
tags:
|
|
- "v*.*.*"
|
|
paths:
|
|
- "**.js"
|
|
- "**.css"
|
|
- "**.html"
|
|
- "**.sh"
|
|
- "**.go"
|
|
- "go.mod"
|
|
- "go.sum"
|
|
- "x-ui.service.debian"
|
|
- "x-ui.service.arch"
|
|
- "x-ui.service.rhel"
|
|
pull_request:
|
|
|
|
jobs:
|
|
build:
|
|
permissions:
|
|
contents: write
|
|
strategy:
|
|
matrix:
|
|
platform:
|
|
- amd64
|
|
- arm64
|
|
- armv7
|
|
- armv6
|
|
- 386
|
|
- armv5
|
|
- s390x
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v6
|
|
|
|
- name: Setup Go
|
|
uses: actions/setup-go@v6
|
|
with:
|
|
go-version-file: go.mod
|
|
check-latest: true
|
|
|
|
# Frontend dist must be built BEFORE go build — Go's //go:embed
|
|
# all:dist directive in web/web.go requires web/dist/ to exist
|
|
# at compile time. web/dist/ is .gitignored, so on a fresh CI
|
|
# checkout it doesn't exist until vite emits it.
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v6
|
|
with:
|
|
node-version: '22'
|
|
cache: 'npm'
|
|
cache-dependency-path: frontend/package-lock.json
|
|
|
|
- name: Build frontend bundle
|
|
run: |
|
|
npm ci
|
|
npm run build
|
|
working-directory: frontend
|
|
|
|
- name: Build 3X-UI
|
|
run: |
|
|
export CGO_ENABLED=1
|
|
export GOOS=linux
|
|
export GOARCH=${{ matrix.platform }}
|
|
# Use Bootlin prebuilt cross-toolchains (musl 1.2.5 in stable series)
|
|
case "${{ matrix.platform }}" in
|
|
amd64) BOOTLIN_ARCH="x86-64" ;;
|
|
arm64) BOOTLIN_ARCH="aarch64" ;;
|
|
armv7) BOOTLIN_ARCH="armv7-eabihf"; export GOARCH=arm GOARM=7 ;;
|
|
armv6) BOOTLIN_ARCH="armv6-eabihf"; export GOARCH=arm GOARM=6 ;;
|
|
armv5) BOOTLIN_ARCH="armv5-eabi"; export GOARCH=arm GOARM=5 ;;
|
|
386) BOOTLIN_ARCH="x86-i686" ;;
|
|
s390x) BOOTLIN_ARCH="s390x-z13" ;;
|
|
esac
|
|
echo "Resolving Bootlin musl toolchain for arch=$BOOTLIN_ARCH (platform=${{ matrix.platform }})"
|
|
TARBALL_BASE="https://toolchains.bootlin.com/downloads/releases/toolchains/$BOOTLIN_ARCH/tarballs/"
|
|
TARBALL_URL=$(curl -fsSL "$TARBALL_BASE" | grep -oE "${BOOTLIN_ARCH}--musl--stable-[^\"]+\\.tar\\.xz" | sort -r | head -n1)
|
|
[ -z "$TARBALL_URL" ] && { echo "Failed to locate Bootlin musl toolchain for arch=$BOOTLIN_ARCH" >&2; exit 1; }
|
|
echo "Downloading: $TARBALL_URL"
|
|
cd /tmp
|
|
curl -fL -sS -o "$(basename "$TARBALL_URL")" "$TARBALL_BASE/$TARBALL_URL"
|
|
tar -xf "$(basename "$TARBALL_URL")"
|
|
TOOLCHAIN_DIR=$(find . -maxdepth 1 -type d -name "${BOOTLIN_ARCH}--musl--stable-*" | head -n1)
|
|
export PATH="$(realpath "$TOOLCHAIN_DIR")/bin:$PATH"
|
|
export CC=$(realpath "$(find "$TOOLCHAIN_DIR/bin" -name '*-gcc.br_real' -type f -executable | head -n1)")
|
|
[ -z "$CC" ] && { echo "No gcc.br_real found in $TOOLCHAIN_DIR/bin" >&2; exit 1; }
|
|
cd -
|
|
go build -ldflags "-w -s -linkmode external -extldflags '-static'" -o xui-release -v main.go
|
|
file xui-release
|
|
ldd xui-release || echo "Static binary confirmed"
|
|
|
|
mkdir x-ui
|
|
cp xui-release x-ui/
|
|
cp x-ui.service.debian x-ui/
|
|
cp x-ui.service.arch x-ui/
|
|
cp x-ui.service.rhel x-ui/
|
|
cp x-ui.sh x-ui/
|
|
mv x-ui/xui-release x-ui/x-ui
|
|
mkdir x-ui/bin
|
|
cd x-ui/bin
|
|
|
|
# Download dependencies
|
|
Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v26.4.25/"
|
|
if [ "${{ matrix.platform }}" == "amd64" ]; then
|
|
wget -q ${Xray_URL}Xray-linux-64.zip
|
|
unzip Xray-linux-64.zip
|
|
rm -f Xray-linux-64.zip
|
|
elif [ "${{ matrix.platform }}" == "arm64" ]; then
|
|
wget -q ${Xray_URL}Xray-linux-arm64-v8a.zip
|
|
unzip Xray-linux-arm64-v8a.zip
|
|
rm -f Xray-linux-arm64-v8a.zip
|
|
elif [ "${{ matrix.platform }}" == "armv7" ]; then
|
|
wget -q ${Xray_URL}Xray-linux-arm32-v7a.zip
|
|
unzip Xray-linux-arm32-v7a.zip
|
|
rm -f Xray-linux-arm32-v7a.zip
|
|
elif [ "${{ matrix.platform }}" == "armv6" ]; then
|
|
wget -q ${Xray_URL}Xray-linux-arm32-v6.zip
|
|
unzip Xray-linux-arm32-v6.zip
|
|
rm -f Xray-linux-arm32-v6.zip
|
|
elif [ "${{ matrix.platform }}" == "386" ]; then
|
|
wget -q ${Xray_URL}Xray-linux-32.zip
|
|
unzip Xray-linux-32.zip
|
|
rm -f Xray-linux-32.zip
|
|
elif [ "${{ matrix.platform }}" == "armv5" ]; then
|
|
wget -q ${Xray_URL}Xray-linux-arm32-v5.zip
|
|
unzip Xray-linux-arm32-v5.zip
|
|
rm -f Xray-linux-arm32-v5.zip
|
|
elif [ "${{ matrix.platform }}" == "s390x" ]; then
|
|
wget -q ${Xray_URL}Xray-linux-s390x.zip
|
|
unzip Xray-linux-s390x.zip
|
|
rm -f Xray-linux-s390x.zip
|
|
fi
|
|
rm -f geoip.dat geosite.dat
|
|
wget -q https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat
|
|
wget -q https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat
|
|
wget -q -O geoip_IR.dat https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geoip.dat
|
|
wget -q -O geosite_IR.dat https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geosite.dat
|
|
wget -q -O geoip_RU.dat https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geoip.dat
|
|
wget -q -O geosite_RU.dat https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geosite.dat
|
|
mv xray xray-linux-${{ matrix.platform }}
|
|
cd ../..
|
|
|
|
- name: Package
|
|
run: tar -zcvf x-ui-linux-${{ matrix.platform }}.tar.gz x-ui
|
|
|
|
- name: Upload files to Artifacts
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: x-ui-linux-${{ matrix.platform }}
|
|
path: ./x-ui-linux-${{ matrix.platform }}.tar.gz
|
|
|
|
- name: Upload files to GH release
|
|
uses: svenstaro/upload-release-action@v2
|
|
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
|
with:
|
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
|
tag: ${{ github.ref_name }}
|
|
file: x-ui-linux-${{ matrix.platform }}.tar.gz
|
|
asset_name: x-ui-linux-${{ matrix.platform }}.tar.gz
|
|
overwrite: true
|
|
prerelease: true
|
|
|
|
# =================================
|
|
# Windows Build
|
|
# =================================
|
|
build-windows:
|
|
name: Build for Windows
|
|
permissions:
|
|
contents: write
|
|
strategy:
|
|
matrix:
|
|
platform:
|
|
- amd64
|
|
runs-on: windows-latest
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v6
|
|
|
|
- name: Setup Go
|
|
uses: actions/setup-go@v6
|
|
with:
|
|
go-version-file: go.mod
|
|
check-latest: true
|
|
|
|
# Frontend dist must be built BEFORE go build — see comment on the
|
|
# Linux job above. This step is identical except npm runs on the
|
|
# Windows runner here.
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v6
|
|
with:
|
|
node-version: '22'
|
|
cache: 'npm'
|
|
cache-dependency-path: frontend/package-lock.json
|
|
|
|
- name: Build frontend bundle
|
|
shell: pwsh
|
|
run: |
|
|
npm ci
|
|
npm run build
|
|
working-directory: frontend
|
|
|
|
- name: Install MSYS2
|
|
uses: msys2/setup-msys2@v2
|
|
with:
|
|
msystem: MINGW64
|
|
update: true
|
|
install: >-
|
|
mingw-w64-x86_64-gcc
|
|
mingw-w64-x86_64-sqlite3
|
|
mingw-w64-x86_64-pkg-config
|
|
|
|
- name: Build 3X-UI for Windows (CGO)
|
|
shell: msys2 {0}
|
|
run: |
|
|
export PATH="/c/hostedtoolcache/windows/go/$(ls /c/hostedtoolcache/windows/go | sort -V | tail -n1)/x64/bin:$PATH"
|
|
|
|
export CGO_ENABLED=1
|
|
export GOOS=windows
|
|
export GOARCH=amd64
|
|
export CC=x86_64-w64-mingw32-gcc
|
|
|
|
which go
|
|
go version
|
|
gcc --version
|
|
|
|
go build -ldflags "-w -s" -o xui-release.exe -v main.go
|
|
|
|
- name: Copy and download resources
|
|
shell: pwsh
|
|
run: |
|
|
mkdir x-ui
|
|
Copy-Item xui-release.exe x-ui\x-ui.exe
|
|
mkdir x-ui\bin
|
|
cd x-ui\bin
|
|
|
|
# Download Xray for Windows
|
|
$Xray_URL = "https://github.com/XTLS/Xray-core/releases/download/v26.4.25/"
|
|
Invoke-WebRequest -Uri "${Xray_URL}Xray-windows-64.zip" -OutFile "Xray-windows-64.zip"
|
|
Expand-Archive -Path "Xray-windows-64.zip" -DestinationPath .
|
|
Remove-Item "Xray-windows-64.zip"
|
|
Remove-Item geoip.dat, geosite.dat -ErrorAction SilentlyContinue
|
|
Invoke-WebRequest -Uri "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat" -OutFile "geoip.dat"
|
|
Invoke-WebRequest -Uri "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat" -OutFile "geosite.dat"
|
|
Invoke-WebRequest -Uri "https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geoip.dat" -OutFile "geoip_IR.dat"
|
|
Invoke-WebRequest -Uri "https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geosite.dat" -OutFile "geosite_IR.dat"
|
|
Invoke-WebRequest -Uri "https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geoip.dat" -OutFile "geoip_RU.dat"
|
|
Invoke-WebRequest -Uri "https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geosite.dat" -OutFile "geosite_RU.dat"
|
|
Rename-Item xray.exe xray-windows-amd64.exe
|
|
cd ..
|
|
Copy-Item -Path ..\windows_files\* -Destination . -Recurse
|
|
cd ..
|
|
|
|
- name: Package to Zip
|
|
shell: pwsh
|
|
run: |
|
|
Compress-Archive -Path .\x-ui -DestinationPath "x-ui-windows-amd64.zip"
|
|
|
|
- name: Upload files to Artifacts
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: x-ui-windows-amd64
|
|
path: ./x-ui-windows-amd64.zip
|
|
|
|
- name: Upload files to GH release
|
|
uses: svenstaro/upload-release-action@v2
|
|
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
|
with:
|
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
|
tag: ${{ github.ref_name }}
|
|
file: x-ui-windows-amd64.zip
|
|
asset_name: x-ui-windows-amd64.zip
|
|
overwrite: true
|
|
prerelease: true
|