linux.yml 10 KB

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