release.yml 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. name: Release 3X-UI
  2. on:
  3. workflow_dispatch:
  4. push:
  5. branches:
  6. - "**"
  7. tags:
  8. - "v*.*.*"
  9. paths:
  10. - "**.go"
  11. - "go.mod"
  12. - "go.sum"
  13. - "**.sh"
  14. - "frontend/**"
  15. - "x-ui.service.debian"
  16. - "x-ui.service.arch"
  17. - "x-ui.service.rhel"
  18. pull_request:
  19. paths:
  20. - "**.go"
  21. - "go.mod"
  22. - "go.sum"
  23. - "**.sh"
  24. - "frontend/**"
  25. - "x-ui.service.debian"
  26. - "x-ui.service.arch"
  27. - "x-ui.service.rhel"
  28. jobs:
  29. build:
  30. permissions:
  31. contents: write
  32. strategy:
  33. matrix:
  34. platform:
  35. - amd64
  36. - arm64
  37. - armv7
  38. - armv6
  39. - 386
  40. - armv5
  41. - s390x
  42. runs-on: ubuntu-latest
  43. steps:
  44. - name: Checkout repository
  45. uses: actions/checkout@v6
  46. - name: Setup Go
  47. uses: actions/setup-go@v6
  48. with:
  49. go-version-file: go.mod
  50. check-latest: true
  51. # Frontend dist must be built BEFORE go build — Go's //go:embed
  52. # all:dist directive in web/web.go requires web/dist/ to exist
  53. # at compile time. web/dist/ is .gitignored, so on a fresh CI
  54. # checkout it doesn't exist until vite emits it.
  55. - name: Setup Node.js
  56. uses: actions/setup-node@v6
  57. with:
  58. node-version: '22'
  59. cache: 'npm'
  60. cache-dependency-path: frontend/package-lock.json
  61. - name: Build frontend bundle
  62. run: |
  63. npm ci
  64. npm run build
  65. working-directory: frontend
  66. - name: Build 3X-UI
  67. run: |
  68. export CGO_ENABLED=1
  69. export GOOS=linux
  70. export GOARCH=${{ matrix.platform }}
  71. # Use Bootlin prebuilt cross-toolchains (musl 1.2.5 in stable series)
  72. case "${{ matrix.platform }}" in
  73. amd64) BOOTLIN_ARCH="x86-64" ;;
  74. arm64) BOOTLIN_ARCH="aarch64" ;;
  75. armv7) BOOTLIN_ARCH="armv7-eabihf"; export GOARCH=arm GOARM=7 ;;
  76. armv6) BOOTLIN_ARCH="armv6-eabihf"; export GOARCH=arm GOARM=6 ;;
  77. armv5) BOOTLIN_ARCH="armv5-eabi"; export GOARCH=arm GOARM=5 ;;
  78. 386) BOOTLIN_ARCH="x86-i686" ;;
  79. s390x) BOOTLIN_ARCH="s390x-z13" ;;
  80. esac
  81. echo "Resolving Bootlin musl toolchain for arch=$BOOTLIN_ARCH (platform=${{ matrix.platform }})"
  82. TARBALL_BASE="https://toolchains.bootlin.com/downloads/releases/toolchains/$BOOTLIN_ARCH/tarballs/"
  83. TARBALL_URL=$(curl -fsSL "$TARBALL_BASE" | grep -oE "${BOOTLIN_ARCH}--musl--stable-[^\"]+\\.tar\\.xz" | sort -r | head -n1)
  84. [ -z "$TARBALL_URL" ] && { echo "Failed to locate Bootlin musl toolchain for arch=$BOOTLIN_ARCH" >&2; exit 1; }
  85. echo "Downloading: $TARBALL_URL"
  86. cd /tmp
  87. curl -fL -sS -o "$(basename "$TARBALL_URL")" "$TARBALL_BASE/$TARBALL_URL"
  88. tar -xf "$(basename "$TARBALL_URL")"
  89. TOOLCHAIN_DIR=$(find . -maxdepth 1 -type d -name "${BOOTLIN_ARCH}--musl--stable-*" | head -n1)
  90. export PATH="$(realpath "$TOOLCHAIN_DIR")/bin:$PATH"
  91. export CC=$(realpath "$(find "$TOOLCHAIN_DIR/bin" -name '*-gcc.br_real' -type f -executable | head -n1)")
  92. [ -z "$CC" ] && { echo "No gcc.br_real found in $TOOLCHAIN_DIR/bin" >&2; exit 1; }
  93. cd -
  94. go build -ldflags "-w -s -linkmode external -extldflags '-static'" -o xui-release -v main.go
  95. file xui-release
  96. ldd xui-release || echo "Static binary confirmed"
  97. mkdir x-ui
  98. cp xui-release x-ui/
  99. cp x-ui.service.debian x-ui/
  100. cp x-ui.service.arch x-ui/
  101. cp x-ui.service.rhel x-ui/
  102. cp x-ui.sh x-ui/
  103. mv x-ui/xui-release x-ui/x-ui
  104. mkdir x-ui/bin
  105. cd x-ui/bin
  106. # Download dependencies
  107. Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v26.6.1/"
  108. if [ "${{ matrix.platform }}" == "amd64" ]; then
  109. wget -q ${Xray_URL}Xray-linux-64.zip
  110. unzip Xray-linux-64.zip
  111. rm -f Xray-linux-64.zip
  112. elif [ "${{ matrix.platform }}" == "arm64" ]; then
  113. wget -q ${Xray_URL}Xray-linux-arm64-v8a.zip
  114. unzip Xray-linux-arm64-v8a.zip
  115. rm -f Xray-linux-arm64-v8a.zip
  116. elif [ "${{ matrix.platform }}" == "armv7" ]; then
  117. wget -q ${Xray_URL}Xray-linux-arm32-v7a.zip
  118. unzip Xray-linux-arm32-v7a.zip
  119. rm -f Xray-linux-arm32-v7a.zip
  120. elif [ "${{ matrix.platform }}" == "armv6" ]; then
  121. wget -q ${Xray_URL}Xray-linux-arm32-v6.zip
  122. unzip Xray-linux-arm32-v6.zip
  123. rm -f Xray-linux-arm32-v6.zip
  124. elif [ "${{ matrix.platform }}" == "386" ]; then
  125. wget -q ${Xray_URL}Xray-linux-32.zip
  126. unzip Xray-linux-32.zip
  127. rm -f Xray-linux-32.zip
  128. elif [ "${{ matrix.platform }}" == "armv5" ]; then
  129. wget -q ${Xray_URL}Xray-linux-arm32-v5.zip
  130. unzip Xray-linux-arm32-v5.zip
  131. rm -f Xray-linux-arm32-v5.zip
  132. elif [ "${{ matrix.platform }}" == "s390x" ]; then
  133. wget -q ${Xray_URL}Xray-linux-s390x.zip
  134. unzip Xray-linux-s390x.zip
  135. rm -f Xray-linux-s390x.zip
  136. fi
  137. rm -f geoip.dat geosite.dat
  138. wget -q https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat
  139. wget -q https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat
  140. wget -q -O geoip_IR.dat https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geoip.dat
  141. wget -q -O geosite_IR.dat https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geosite.dat
  142. wget -q -O geoip_RU.dat https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geoip.dat
  143. wget -q -O geosite_RU.dat https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geosite.dat
  144. mv xray xray-linux-${{ matrix.platform }}
  145. # mtg (MTProto sidecar) - only for arches mtg publishes
  146. MTG_VER="2.2.8"
  147. case "${{ matrix.platform }}" in
  148. amd64|arm64|armv7|armv6|386)
  149. wget -q "https://github.com/9seconds/mtg/releases/download/v${MTG_VER}/mtg-${MTG_VER}-linux-${{ matrix.platform }}.tar.gz"
  150. tar -xzf "mtg-${MTG_VER}-linux-${{ matrix.platform }}.tar.gz"
  151. mv "mtg-${MTG_VER}-linux-${{ matrix.platform }}/mtg" "mtg-linux-${{ matrix.platform }}" 2>/dev/null || mv mtg "mtg-linux-${{ matrix.platform }}"
  152. rm -rf "mtg-${MTG_VER}-linux-${{ matrix.platform }}" "mtg-${MTG_VER}-linux-${{ matrix.platform }}.tar.gz"
  153. ;;
  154. esac
  155. cd ../..
  156. - name: Package
  157. run: tar -zcvf x-ui-linux-${{ matrix.platform }}.tar.gz x-ui
  158. - name: Upload files to Artifacts
  159. uses: actions/upload-artifact@v7
  160. with:
  161. name: x-ui-linux-${{ matrix.platform }}
  162. path: ./x-ui-linux-${{ matrix.platform }}.tar.gz
  163. - name: Upload files to GH release
  164. uses: svenstaro/upload-release-action@v2
  165. if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
  166. with:
  167. repo_token: ${{ secrets.GITHUB_TOKEN }}
  168. tag: ${{ github.ref_name }}
  169. file: x-ui-linux-${{ matrix.platform }}.tar.gz
  170. asset_name: x-ui-linux-${{ matrix.platform }}.tar.gz
  171. overwrite: true
  172. prerelease: true
  173. # =================================
  174. # Windows Build
  175. # =================================
  176. build-windows:
  177. name: Build for Windows
  178. permissions:
  179. contents: write
  180. strategy:
  181. matrix:
  182. platform:
  183. - amd64
  184. runs-on: windows-latest
  185. steps:
  186. - name: Checkout repository
  187. uses: actions/checkout@v6
  188. - name: Setup Go
  189. uses: actions/setup-go@v6
  190. with:
  191. go-version-file: go.mod
  192. check-latest: true
  193. # Frontend dist must be built BEFORE go build — see comment on the
  194. # Linux job above. This step is identical except npm runs on the
  195. # Windows runner here.
  196. - name: Setup Node.js
  197. uses: actions/setup-node@v6
  198. with:
  199. node-version: '22'
  200. cache: 'npm'
  201. cache-dependency-path: frontend/package-lock.json
  202. - name: Build frontend bundle
  203. shell: pwsh
  204. run: |
  205. npm ci
  206. npm run build
  207. working-directory: frontend
  208. - name: Install MSYS2
  209. uses: msys2/setup-msys2@v2
  210. with:
  211. msystem: MINGW64
  212. update: true
  213. install: >-
  214. mingw-w64-x86_64-gcc
  215. mingw-w64-x86_64-sqlite3
  216. mingw-w64-x86_64-pkg-config
  217. - name: Build 3X-UI for Windows (CGO)
  218. shell: msys2 {0}
  219. run: |
  220. export PATH="/c/hostedtoolcache/windows/go/$(ls /c/hostedtoolcache/windows/go | sort -V | tail -n1)/x64/bin:$PATH"
  221. export CGO_ENABLED=1
  222. export GOOS=windows
  223. export GOARCH=amd64
  224. export CC=x86_64-w64-mingw32-gcc
  225. which go
  226. go version
  227. gcc --version
  228. go build -ldflags "-w -s" -o xui-release.exe -v main.go
  229. - name: Copy and download resources
  230. shell: pwsh
  231. run: |
  232. mkdir x-ui
  233. Copy-Item xui-release.exe x-ui\x-ui.exe
  234. mkdir x-ui\bin
  235. cd x-ui\bin
  236. # Download Xray for Windows
  237. $Xray_URL = "https://github.com/XTLS/Xray-core/releases/download/v26.6.1/"
  238. Invoke-WebRequest -Uri "${Xray_URL}Xray-windows-64.zip" -OutFile "Xray-windows-64.zip"
  239. Expand-Archive -Path "Xray-windows-64.zip" -DestinationPath .
  240. Remove-Item "Xray-windows-64.zip"
  241. Remove-Item geoip.dat, geosite.dat -ErrorAction SilentlyContinue
  242. Invoke-WebRequest -Uri "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat" -OutFile "geoip.dat"
  243. Invoke-WebRequest -Uri "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat" -OutFile "geosite.dat"
  244. Invoke-WebRequest -Uri "https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geoip.dat" -OutFile "geoip_IR.dat"
  245. Invoke-WebRequest -Uri "https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geosite.dat" -OutFile "geosite_IR.dat"
  246. Invoke-WebRequest -Uri "https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geoip.dat" -OutFile "geoip_RU.dat"
  247. Invoke-WebRequest -Uri "https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geosite.dat" -OutFile "geosite_RU.dat"
  248. Rename-Item xray.exe xray-windows-amd64.exe
  249. # Download mtg (MTProto sidecar) for Windows
  250. $MTG_VER = "2.2.8"
  251. Invoke-WebRequest -Uri "https://github.com/9seconds/mtg/releases/download/v$MTG_VER/mtg-$MTG_VER-windows-amd64.zip" -OutFile "mtg-windows-amd64.zip"
  252. Expand-Archive -Path "mtg-windows-amd64.zip" -DestinationPath "mtg-tmp"
  253. $mtgExe = Get-ChildItem -Path "mtg-tmp" -Recurse -Filter "mtg.exe" | Select-Object -First 1
  254. Move-Item $mtgExe.FullName "mtg-windows-amd64.exe"
  255. Remove-Item "mtg-windows-amd64.zip", "mtg-tmp" -Recurse -Force
  256. cd ..
  257. Copy-Item -Path ..\windows_files\* -Destination . -Recurse
  258. cd ..
  259. - name: Package to Zip
  260. shell: pwsh
  261. run: |
  262. Compress-Archive -Path .\x-ui -DestinationPath "x-ui-windows-amd64.zip"
  263. - name: Upload files to Artifacts
  264. uses: actions/upload-artifact@v7
  265. with:
  266. name: x-ui-windows-amd64
  267. path: ./x-ui-windows-amd64.zip
  268. - name: Upload files to GH release
  269. uses: svenstaro/upload-release-action@v2
  270. if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
  271. with:
  272. repo_token: ${{ secrets.GITHUB_TOKEN }}
  273. tag: ${{ github.ref_name }}
  274. file: x-ui-windows-amd64.zip
  275. asset_name: x-ui-windows-amd64.zip
  276. overwrite: true
  277. prerelease: true