release.yml 10 KB

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