linux.yml 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. name: Build Linux Packages
  2. on:
  3. #push:
  4. # branches:
  5. # - main-next
  6. # - dev-next
  7. workflow_dispatch:
  8. inputs:
  9. version:
  10. description: "Version name"
  11. required: true
  12. type: string
  13. forceBeta:
  14. description: "Force beta"
  15. required: false
  16. type: boolean
  17. default: false
  18. release:
  19. types:
  20. - published
  21. jobs:
  22. calculate_version:
  23. name: Calculate version
  24. runs-on: ubuntu-latest
  25. outputs:
  26. version: ${{ steps.outputs.outputs.version }}
  27. steps:
  28. - name: Checkout
  29. uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
  30. with:
  31. fetch-depth: 0
  32. - name: Setup Go
  33. uses: actions/setup-go@v5
  34. with:
  35. go-version: ^1.25.5
  36. - name: Check input version
  37. if: github.event_name == 'workflow_dispatch'
  38. run: |-
  39. echo "version=${{ inputs.version }}"
  40. echo "version=${{ inputs.version }}" >> "$GITHUB_ENV"
  41. - name: Calculate version
  42. if: github.event_name != 'workflow_dispatch'
  43. run: |-
  44. go run -v ./cmd/internal/read_tag --ci --nightly
  45. - name: Set outputs
  46. id: outputs
  47. run: |-
  48. echo "version=$version" >> "$GITHUB_OUTPUT"
  49. build:
  50. name: Build binary
  51. runs-on: ubuntu-latest
  52. needs:
  53. - calculate_version
  54. strategy:
  55. matrix:
  56. include:
  57. # Naive-enabled builds (musl)
  58. - { os: linux, arch: amd64, naive: true, debian: amd64, rpm: x86_64, pacman: x86_64 }
  59. - { os: linux, arch: arm64, naive: true, debian: arm64, rpm: aarch64, pacman: aarch64 }
  60. - { os: linux, arch: "386", naive: true, debian: i386, rpm: i386 }
  61. - { os: linux, arch: arm, goarm: "7", naive: true, debian: armhf, rpm: armv7hl, pacman: armv7hl }
  62. # Non-naive builds (unsupported architectures)
  63. - { os: linux, arch: arm, goarm: "6", debian: armel, rpm: armv6hl }
  64. - { os: linux, arch: mips64le, debian: mips64el, rpm: mips64el }
  65. - { os: linux, arch: mipsle, debian: mipsel, rpm: mipsel }
  66. - { os: linux, arch: s390x, debian: s390x, rpm: s390x }
  67. - { os: linux, arch: ppc64le, debian: ppc64el, rpm: ppc64le }
  68. - { os: linux, arch: riscv64, debian: riscv64, rpm: riscv64 }
  69. - { os: linux, arch: loong64, debian: loongarch64, rpm: loongarch64 }
  70. steps:
  71. - name: Checkout
  72. uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
  73. with:
  74. fetch-depth: 0
  75. - name: Setup Go
  76. uses: actions/setup-go@v5
  77. with:
  78. go-version: ^1.25.5
  79. - name: Clone cronet-go
  80. if: matrix.naive
  81. run: |
  82. set -xeuo pipefail
  83. CRONET_GO_VERSION=$(cat .github/CRONET_GO_VERSION)
  84. git init ~/cronet-go
  85. git -C ~/cronet-go remote add origin https://github.com/sagernet/cronet-go.git
  86. git -C ~/cronet-go fetch --depth=1 origin "$CRONET_GO_VERSION"
  87. git -C ~/cronet-go checkout FETCH_HEAD
  88. git -C ~/cronet-go submodule update --init --recursive --depth=1
  89. - name: Cache Chromium toolchain
  90. if: matrix.naive
  91. id: cache-chromium-toolchain
  92. uses: actions/cache@v4
  93. with:
  94. path: |
  95. ~/cronet-go/naiveproxy/src/third_party/llvm-build/Release+Asserts
  96. ~/cronet-go/naiveproxy/src/out/sysroot-build
  97. key: chromium-toolchain-${{ matrix.arch }}-musl-${{ hashFiles('.github/CRONET_GO_VERSION') }}
  98. - name: Download Chromium toolchain
  99. if: matrix.naive
  100. run: |
  101. set -xeuo pipefail
  102. cd ~/cronet-go
  103. go run ./cmd/build-naive --target=linux/${{ matrix.arch }} --libc=musl download-toolchain
  104. - name: Set Chromium toolchain environment
  105. if: matrix.naive
  106. run: |
  107. set -xeuo pipefail
  108. cd ~/cronet-go
  109. go run ./cmd/build-naive --target=linux/${{ matrix.arch }} --libc=musl env >> $GITHUB_ENV
  110. - name: Set tag
  111. run: |-
  112. git ls-remote --exit-code --tags origin v${{ needs.calculate_version.outputs.version }} || echo "PUBLISHED=false" >> "$GITHUB_ENV"
  113. git tag v${{ needs.calculate_version.outputs.version }} -f
  114. - name: Set build tags
  115. run: |
  116. set -xeuo pipefail
  117. TAGS='with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_ocm,badlinkname,tfogo_checklinkname0'
  118. if [[ "${{ matrix.naive }}" == "true" ]]; then
  119. TAGS="${TAGS},with_naive_outbound,with_musl"
  120. fi
  121. echo "BUILD_TAGS=${TAGS}" >> "${GITHUB_ENV}"
  122. - name: Build (naive)
  123. if: matrix.naive
  124. run: |
  125. set -xeuo pipefail
  126. mkdir -p dist
  127. go build -v -trimpath -o dist/sing-box -tags "${BUILD_TAGS}" \
  128. -ldflags '-s -buildid= -X github.com/sagernet/sing-box/constant.Version=${{ needs.calculate_version.outputs.version }} -checklinkname=0' \
  129. ./cmd/sing-box
  130. env:
  131. CGO_ENABLED: "1"
  132. GOOS: linux
  133. GOARCH: ${{ matrix.arch }}
  134. GOARM: ${{ matrix.goarm }}
  135. GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  136. - name: Build (non-naive)
  137. if: ${{ ! matrix.naive }}
  138. run: |
  139. set -xeuo pipefail
  140. mkdir -p dist
  141. go build -v -trimpath -o dist/sing-box -tags "${BUILD_TAGS}" \
  142. -ldflags '-s -buildid= -X github.com/sagernet/sing-box/constant.Version=${{ needs.calculate_version.outputs.version }} -checklinkname=0' \
  143. ./cmd/sing-box
  144. env:
  145. CGO_ENABLED: "0"
  146. GOOS: ${{ matrix.os }}
  147. GOARCH: ${{ matrix.arch }}
  148. GOARM: ${{ matrix.goarm }}
  149. GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  150. - name: Set mtime
  151. run: |-
  152. TZ=UTC touch -t '197001010000' dist/sing-box
  153. - name: Set name
  154. if: (! contains(needs.calculate_version.outputs.version, '-')) && !inputs.forceBeta
  155. run: |-
  156. echo "NAME=sing-box" >> "$GITHUB_ENV"
  157. - name: Set beta name
  158. if: contains(needs.calculate_version.outputs.version, '-') || inputs.forceBeta
  159. run: |-
  160. echo "NAME=sing-box-beta" >> "$GITHUB_ENV"
  161. - name: Set version
  162. run: |-
  163. PKG_VERSION="${{ needs.calculate_version.outputs.version }}"
  164. PKG_VERSION="${PKG_VERSION//-/\~}"
  165. echo "PKG_VERSION=${PKG_VERSION}" >> "${GITHUB_ENV}"
  166. - name: Package DEB
  167. if: matrix.debian != ''
  168. run: |
  169. set -xeuo pipefail
  170. sudo gem install fpm
  171. sudo apt-get install -y debsigs
  172. cp .fpm_systemd .fpm
  173. fpm -t deb \
  174. --name "${NAME}" \
  175. -v "$PKG_VERSION" \
  176. -p "dist/${NAME}_${{ needs.calculate_version.outputs.version }}_linux_${{ matrix.debian }}.deb" \
  177. --architecture ${{ matrix.debian }} \
  178. dist/sing-box=/usr/bin/sing-box
  179. curl -Lo '/tmp/debsigs.diff' 'https://gitlab.com/debsigs/debsigs/-/commit/160138f5de1ec110376d3c807b60a37388bc7c90.diff'
  180. sudo patch /usr/bin/debsigs < '/tmp/debsigs.diff'
  181. rm -rf $HOME/.gnupg
  182. gpg --pinentry-mode loopback --passphrase "${{ secrets.GPG_PASSPHRASE }}" --import <<EOF
  183. ${{ secrets.GPG_KEY }}
  184. EOF
  185. debsigs --sign=origin -k ${{ secrets.GPG_KEY_ID }} --gpgopts '--pinentry-mode loopback --passphrase "${{ secrets.GPG_PASSPHRASE }}"' dist/*.deb
  186. - name: Package RPM
  187. if: matrix.rpm != ''
  188. run: |-
  189. set -xeuo pipefail
  190. sudo gem install fpm
  191. cp .fpm_systemd .fpm
  192. fpm -t rpm \
  193. --name "${NAME}" \
  194. -v "$PKG_VERSION" \
  195. -p "dist/${NAME}_${{ needs.calculate_version.outputs.version }}_linux_${{ matrix.rpm }}.rpm" \
  196. --architecture ${{ matrix.rpm }} \
  197. dist/sing-box=/usr/bin/sing-box
  198. cat > $HOME/.rpmmacros <<EOF
  199. %_gpg_name ${{ secrets.GPG_KEY_ID }}
  200. %_gpg_sign_cmd_extra_args --pinentry-mode loopback --passphrase ${{ secrets.GPG_PASSPHRASE }}
  201. EOF
  202. gpg --pinentry-mode loopback --passphrase "${{ secrets.GPG_PASSPHRASE }}" --import <<EOF
  203. ${{ secrets.GPG_KEY }}
  204. EOF
  205. rpmsign --addsign dist/*.rpm
  206. - name: Cleanup
  207. run: rm dist/sing-box
  208. - name: Upload artifact
  209. uses: actions/upload-artifact@v4
  210. with:
  211. name: binary-${{ matrix.os }}_${{ matrix.arch }}${{ matrix.goarm && format('v{0}', matrix.goarm) }}${{ matrix.legacy_go && '-legacy' || '' }}
  212. path: "dist"
  213. upload:
  214. name: Upload builds
  215. runs-on: ubuntu-latest
  216. needs:
  217. - calculate_version
  218. - build
  219. steps:
  220. - name: Checkout
  221. uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
  222. with:
  223. fetch-depth: 0
  224. - name: Set tag
  225. run: |-
  226. git ls-remote --exit-code --tags origin v${{ needs.calculate_version.outputs.version }} || echo "PUBLISHED=false" >> "$GITHUB_ENV"
  227. git tag v${{ needs.calculate_version.outputs.version }} -f
  228. echo "VERSION=${{ needs.calculate_version.outputs.version }}" >> "$GITHUB_ENV"
  229. - name: Download builds
  230. uses: actions/download-artifact@v5
  231. with:
  232. path: dist
  233. merge-multiple: true
  234. - name: Publish packages
  235. if: github.event_name != 'push'
  236. run: |-
  237. ls dist | xargs -I {} curl -F "package=@dist/{}" https://${{ secrets.FURY_TOKEN }}@push.fury.io/sagernet/