build.yml 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953
  1. name: Build
  2. on:
  3. workflow_dispatch:
  4. inputs:
  5. version:
  6. description: "Version name"
  7. required: true
  8. type: string
  9. build:
  10. description: "Build type"
  11. required: true
  12. type: choice
  13. default: "All"
  14. options:
  15. - All
  16. - Binary
  17. - Android
  18. - Apple
  19. - app-store
  20. - iOS
  21. - macOS
  22. - tvOS
  23. - macOS-standalone
  24. - publish-android
  25. push:
  26. branches:
  27. - main-next
  28. - dev-next
  29. concurrency:
  30. group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}-${{ inputs.build }}
  31. cancel-in-progress: true
  32. jobs:
  33. calculate_version:
  34. name: Calculate version
  35. runs-on: ubuntu-latest
  36. outputs:
  37. version: ${{ steps.outputs.outputs.version }}
  38. steps:
  39. - name: Checkout
  40. uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
  41. with:
  42. fetch-depth: 0
  43. - name: Setup Go
  44. uses: actions/setup-go@v5
  45. with:
  46. go-version: ^1.25.5
  47. - name: Check input version
  48. if: github.event_name == 'workflow_dispatch'
  49. run: |-
  50. echo "version=${{ inputs.version }}"
  51. echo "version=${{ inputs.version }}" >> "$GITHUB_ENV"
  52. - name: Calculate version
  53. if: github.event_name != 'workflow_dispatch'
  54. run: |-
  55. go run -v ./cmd/internal/read_tag --ci --nightly
  56. - name: Set outputs
  57. id: outputs
  58. run: |-
  59. echo "version=$version" >> "$GITHUB_OUTPUT"
  60. build:
  61. name: Build binary
  62. if: github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Binary'
  63. runs-on: ubuntu-latest
  64. needs:
  65. - calculate_version
  66. strategy:
  67. matrix:
  68. include:
  69. - { os: linux, arch: amd64, variant: purego, naive: true, openwrt: "x86_64" }
  70. - { os: linux, arch: amd64, variant: glibc, naive: true }
  71. - { os: linux, arch: amd64, variant: musl, naive: true, debian: amd64, rpm: x86_64, pacman: x86_64, openwrt: "x86_64" }
  72. - { os: linux, arch: arm64, variant: purego, naive: true, openwrt: "aarch64_cortex-a53 aarch64_cortex-a72 aarch64_cortex-a76 aarch64_generic" }
  73. - { os: linux, arch: arm64, variant: glibc, naive: true }
  74. - { os: linux, arch: arm64, variant: musl, naive: true, debian: arm64, rpm: aarch64, pacman: aarch64, openwrt: "aarch64_cortex-a53 aarch64_cortex-a72 aarch64_cortex-a76 aarch64_generic" }
  75. - { os: linux, arch: "386", go386: sse2, openwrt: "i386_pentium4" }
  76. - { os: linux, arch: "386", variant: glibc, naive: true, go386: sse2 }
  77. - { os: linux, arch: "386", variant: musl, naive: true, go386: sse2, debian: i386, rpm: i386, openwrt: "i386_pentium4" }
  78. - { os: linux, arch: arm, goarm: "7", openwrt: "arm_cortex-a5_vfpv4 arm_cortex-a7_neon-vfpv4 arm_cortex-a7_vfpv4 arm_cortex-a8_vfpv3 arm_cortex-a9_neon arm_cortex-a9_vfpv3-d16 arm_cortex-a15_neon-vfpv4" }
  79. - { os: linux, arch: arm, variant: glibc, naive: true, goarm: "7" }
  80. - { os: linux, arch: arm, variant: musl, naive: true, goarm: "7", debian: armhf, rpm: armv7hl, pacman: armv7hl, openwrt: "arm_cortex-a5_vfpv4 arm_cortex-a7_neon-vfpv4 arm_cortex-a7_vfpv4 arm_cortex-a8_vfpv3 arm_cortex-a9_neon arm_cortex-a9_vfpv3-d16 arm_cortex-a15_neon-vfpv4" }
  81. - { os: linux, arch: "386", go386: softfloat, openwrt: "i386_pentium-mmx" }
  82. - { os: linux, arch: arm, goarm: "5", openwrt: "arm_arm926ej-s arm_cortex-a7 arm_cortex-a9 arm_fa526 arm_xscale" }
  83. - { os: linux, arch: arm, goarm: "6", debian: armel, rpm: armv6hl, openwrt: "arm_arm1176jzf-s_vfp" }
  84. - { os: linux, arch: mips, gomips: softfloat, openwrt: "mips_24kc mips_4kec mips_mips32" }
  85. - { os: linux, arch: mipsle, gomips: hardfloat, debian: mipsel, rpm: mipsel, openwrt: "mipsel_24kc_24kf" }
  86. - { os: linux, arch: mipsle, gomips: softfloat, openwrt: "mipsel_24kc mipsel_74kc mipsel_mips32" }
  87. - { os: linux, arch: mips64, gomips: softfloat, openwrt: "mips64_mips64r2 mips64_octeonplus" }
  88. - { os: linux, arch: mips64le, gomips: hardfloat, debian: mips64el, rpm: mips64el }
  89. - { os: linux, arch: mips64le, gomips: softfloat, openwrt: "mips64el_mips64r2" }
  90. - { os: linux, arch: s390x, debian: s390x, rpm: s390x }
  91. - { os: linux, arch: ppc64le, debian: ppc64el, rpm: ppc64le }
  92. - { os: linux, arch: riscv64, debian: riscv64, rpm: riscv64, openwrt: "riscv64_generic" }
  93. - { os: linux, arch: loong64, debian: loongarch64, rpm: loongarch64, openwrt: "loongarch64_generic" }
  94. - { os: windows, arch: amd64, legacy_win7: true, legacy_name: "windows-7" }
  95. - { os: windows, arch: "386", legacy_win7: true, legacy_name: "windows-7" }
  96. - { os: android, arch: arm64, ndk: "aarch64-linux-android23" }
  97. - { os: android, arch: arm, ndk: "armv7a-linux-androideabi23" }
  98. - { os: android, arch: amd64, ndk: "x86_64-linux-android23" }
  99. - { os: android, arch: "386", ndk: "i686-linux-android23" }
  100. steps:
  101. - name: Checkout
  102. uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
  103. with:
  104. fetch-depth: 0
  105. - name: Setup Go
  106. if: ${{ ! (matrix.legacy_win7 || matrix.legacy_go124) }}
  107. uses: actions/setup-go@v5
  108. with:
  109. go-version: ^1.25.5
  110. - name: Setup Go 1.24
  111. if: matrix.legacy_go124
  112. uses: actions/setup-go@v5
  113. with:
  114. go-version: ~1.24.10
  115. - name: Cache Go for Windows 7
  116. if: matrix.legacy_win7
  117. id: cache-go-for-windows7
  118. uses: actions/cache@v4
  119. with:
  120. path: |
  121. ~/go/go_win7
  122. key: go_win7_1255
  123. - name: Setup Go for Windows 7
  124. if: matrix.legacy_win7 && steps.cache-go-for-windows7.outputs.cache-hit != 'true'
  125. run: |-
  126. .github/setup_go_for_windows7.sh
  127. - name: Setup Go for Windows 7
  128. if: matrix.legacy_win7
  129. run: |-
  130. echo "PATH=$HOME/go/go_win7/bin:$PATH" >> $GITHUB_ENV
  131. echo "GOROOT=$HOME/go/go_win7" >> $GITHUB_ENV
  132. - name: Setup Android NDK
  133. if: matrix.os == 'android'
  134. uses: nttld/setup-ndk@v1
  135. with:
  136. ndk-version: r28
  137. local-cache: true
  138. - name: Clone cronet-go
  139. if: matrix.naive
  140. run: |
  141. set -xeuo pipefail
  142. CRONET_GO_VERSION=$(cat .github/CRONET_GO_VERSION)
  143. git init ~/cronet-go
  144. git -C ~/cronet-go remote add origin https://github.com/sagernet/cronet-go.git
  145. git -C ~/cronet-go fetch --depth=1 origin "$CRONET_GO_VERSION"
  146. git -C ~/cronet-go checkout FETCH_HEAD
  147. git -C ~/cronet-go submodule update --init --recursive --depth=1
  148. - name: Cache Chromium toolchain
  149. if: matrix.naive
  150. id: cache-chromium-toolchain
  151. uses: actions/cache@v4
  152. with:
  153. path: |
  154. ~/cronet-go/naiveproxy/src/third_party/llvm-build/Release+Asserts
  155. ~/cronet-go/naiveproxy/src/out/sysroot-build
  156. key: chromium-toolchain-${{ matrix.arch }}-${{ matrix.variant }}-${{ hashFiles('.github/CRONET_GO_VERSION') }}
  157. - name: Download Chromium toolchain
  158. if: matrix.naive
  159. run: |
  160. set -xeuo pipefail
  161. cd ~/cronet-go
  162. if [[ "${{ matrix.variant }}" == "musl" ]]; then
  163. go run ./cmd/build-naive --target=linux/${{ matrix.arch }} --libc=musl download-toolchain
  164. else
  165. go run ./cmd/build-naive --target=linux/${{ matrix.arch }} download-toolchain
  166. fi
  167. - name: Set Chromium toolchain environment
  168. if: matrix.naive
  169. run: |
  170. set -xeuo pipefail
  171. cd ~/cronet-go
  172. if [[ "${{ matrix.variant }}" == "musl" ]]; then
  173. go run ./cmd/build-naive --target=linux/${{ matrix.arch }} --libc=musl env >> $GITHUB_ENV
  174. else
  175. go run ./cmd/build-naive --target=linux/${{ matrix.arch }} env >> $GITHUB_ENV
  176. fi
  177. - name: Set tag
  178. run: |-
  179. git ls-remote --exit-code --tags origin v${{ needs.calculate_version.outputs.version }} || echo "PUBLISHED=false" >> "$GITHUB_ENV"
  180. git tag v${{ needs.calculate_version.outputs.version }} -f
  181. - name: Set build tags
  182. run: |
  183. set -xeuo pipefail
  184. 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'
  185. if [[ "${{ matrix.naive }}" == "true" ]]; then
  186. TAGS="${TAGS},with_naive_outbound"
  187. fi
  188. if [[ "${{ matrix.variant }}" == "purego" ]]; then
  189. TAGS="${TAGS},with_purego"
  190. elif [[ "${{ matrix.variant }}" == "musl" ]]; then
  191. TAGS="${TAGS},with_musl"
  192. fi
  193. echo "BUILD_TAGS=${TAGS}" >> "${GITHUB_ENV}"
  194. - name: Build (purego)
  195. if: matrix.variant == 'purego'
  196. run: |
  197. set -xeuo pipefail
  198. mkdir -p dist
  199. go build -v -trimpath -o dist/sing-box -tags "${BUILD_TAGS}" \
  200. -ldflags '-s -buildid= -X github.com/sagernet/sing-box/constant.Version=${{ needs.calculate_version.outputs.version }} -checklinkname=0' \
  201. ./cmd/sing-box
  202. env:
  203. CGO_ENABLED: "0"
  204. GOOS: ${{ matrix.os }}
  205. GOARCH: ${{ matrix.arch }}
  206. GO386: ${{ matrix.go386 }}
  207. GOARM: ${{ matrix.goarm }}
  208. GOMIPS: ${{ matrix.gomips }}
  209. GOMIPS64: ${{ matrix.gomips }}
  210. GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  211. - name: Extract libcronet.so
  212. if: matrix.variant == 'purego' && matrix.naive
  213. run: |
  214. cd ~/cronet-go
  215. CGO_ENABLED=0 go run -v ./cmd/build-naive extract-lib --target ${{ matrix.os }}/${{ matrix.arch }} -o $GITHUB_WORKSPACE/dist
  216. - name: Build (glibc)
  217. if: matrix.variant == 'glibc'
  218. run: |
  219. set -xeuo pipefail
  220. mkdir -p dist
  221. go build -v -trimpath -o dist/sing-box -tags "${BUILD_TAGS}" \
  222. -ldflags '-s -buildid= -X github.com/sagernet/sing-box/constant.Version=${{ needs.calculate_version.outputs.version }} -checklinkname=0' \
  223. ./cmd/sing-box
  224. env:
  225. CGO_ENABLED: "1"
  226. GOOS: linux
  227. GOARCH: ${{ matrix.arch }}
  228. GO386: ${{ matrix.go386 }}
  229. GOARM: ${{ matrix.goarm }}
  230. GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  231. - name: Build (musl)
  232. if: matrix.variant == 'musl'
  233. run: |
  234. set -xeuo pipefail
  235. mkdir -p dist
  236. go build -v -trimpath -o dist/sing-box -tags "${BUILD_TAGS}" \
  237. -ldflags '-s -buildid= -X github.com/sagernet/sing-box/constant.Version=${{ needs.calculate_version.outputs.version }} -checklinkname=0' \
  238. ./cmd/sing-box
  239. env:
  240. CGO_ENABLED: "1"
  241. GOOS: linux
  242. GOARCH: ${{ matrix.arch }}
  243. GO386: ${{ matrix.go386 }}
  244. GOARM: ${{ matrix.goarm }}
  245. GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  246. - name: Build (non-variant)
  247. if: matrix.os != 'android' && matrix.variant == ''
  248. run: |
  249. set -xeuo pipefail
  250. mkdir -p dist
  251. go build -v -trimpath -o dist/sing-box -tags "${BUILD_TAGS}" \
  252. -ldflags '-s -buildid= -X github.com/sagernet/sing-box/constant.Version=${{ needs.calculate_version.outputs.version }} -checklinkname=0' \
  253. ./cmd/sing-box
  254. env:
  255. CGO_ENABLED: "0"
  256. GOOS: ${{ matrix.os }}
  257. GOARCH: ${{ matrix.arch }}
  258. GO386: ${{ matrix.go386 }}
  259. GOARM: ${{ matrix.goarm }}
  260. GOMIPS: ${{ matrix.gomips }}
  261. GOMIPS64: ${{ matrix.gomips }}
  262. GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  263. - name: Build Android
  264. if: matrix.os == 'android'
  265. run: |
  266. set -xeuo pipefail
  267. go install -v ./cmd/internal/build
  268. export CC='${{ matrix.ndk }}-clang'
  269. export CXX="${CC}++"
  270. mkdir -p dist
  271. GOOS=$BUILD_GOOS GOARCH=$BUILD_GOARCH build go build -v -trimpath -o dist/sing-box -tags "${BUILD_TAGS}" \
  272. -ldflags '-s -buildid= -X github.com/sagernet/sing-box/constant.Version=${{ needs.calculate_version.outputs.version }} -checklinkname=0' \
  273. ./cmd/sing-box
  274. env:
  275. CGO_ENABLED: "1"
  276. BUILD_GOOS: ${{ matrix.os }}
  277. BUILD_GOARCH: ${{ matrix.arch }}
  278. GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  279. - name: Set name
  280. run: |-
  281. DIR_NAME="sing-box-${{ needs.calculate_version.outputs.version }}-${{ matrix.os }}-${{ matrix.arch }}"
  282. if [[ -n "${{ matrix.goarm }}" ]]; then
  283. DIR_NAME="${DIR_NAME}v${{ matrix.goarm }}"
  284. elif [[ -n "${{ matrix.go386 }}" && "${{ matrix.go386 }}" != 'sse2' ]]; then
  285. DIR_NAME="${DIR_NAME}-${{ matrix.go386 }}"
  286. elif [[ -n "${{ matrix.gomips }}" && "${{ matrix.gomips }}" != 'hardfloat' ]]; then
  287. DIR_NAME="${DIR_NAME}-${{ matrix.gomips }}"
  288. elif [[ -n "${{ matrix.legacy_name }}" ]]; then
  289. DIR_NAME="${DIR_NAME}-legacy-${{ matrix.legacy_name }}"
  290. fi
  291. if [[ "${{ matrix.variant }}" == "glibc" ]]; then
  292. DIR_NAME="${DIR_NAME}-glibc"
  293. elif [[ "${{ matrix.variant }}" == "musl" ]]; then
  294. DIR_NAME="${DIR_NAME}-musl"
  295. fi
  296. echo "DIR_NAME=${DIR_NAME}" >> "${GITHUB_ENV}"
  297. PKG_VERSION="${{ needs.calculate_version.outputs.version }}"
  298. PKG_VERSION="${PKG_VERSION//-/\~}"
  299. echo "PKG_VERSION=${PKG_VERSION}" >> "${GITHUB_ENV}"
  300. - name: Package DEB
  301. if: matrix.debian != ''
  302. run: |
  303. set -xeuo pipefail
  304. sudo gem install fpm
  305. sudo apt-get update
  306. sudo apt-get install -y debsigs
  307. cp .fpm_systemd .fpm
  308. fpm -t deb \
  309. -v "$PKG_VERSION" \
  310. -p "dist/sing-box_${{ needs.calculate_version.outputs.version }}_${{ matrix.os }}_${{ matrix.debian }}.deb" \
  311. --architecture ${{ matrix.debian }} \
  312. dist/sing-box=/usr/bin/sing-box
  313. curl -Lo '/tmp/debsigs.diff' 'https://gitlab.com/debsigs/debsigs/-/commit/160138f5de1ec110376d3c807b60a37388bc7c90.diff'
  314. sudo patch /usr/bin/debsigs < '/tmp/debsigs.diff'
  315. rm -rf $HOME/.gnupg
  316. gpg --pinentry-mode loopback --passphrase "${{ secrets.GPG_PASSPHRASE }}" --import <<EOF
  317. ${{ secrets.GPG_KEY }}
  318. EOF
  319. debsigs --sign=origin -k ${{ secrets.GPG_KEY_ID }} --gpgopts '--pinentry-mode loopback --passphrase "${{ secrets.GPG_PASSPHRASE }}"' dist/*.deb
  320. - name: Package RPM
  321. if: matrix.rpm != ''
  322. run: |-
  323. set -xeuo pipefail
  324. sudo gem install fpm
  325. cp .fpm_systemd .fpm
  326. fpm -t rpm \
  327. -v "$PKG_VERSION" \
  328. -p "dist/sing-box_${{ needs.calculate_version.outputs.version }}_${{ matrix.os }}_${{ matrix.rpm }}.rpm" \
  329. --architecture ${{ matrix.rpm }} \
  330. dist/sing-box=/usr/bin/sing-box
  331. cat > $HOME/.rpmmacros <<EOF
  332. %_gpg_name ${{ secrets.GPG_KEY_ID }}
  333. %_gpg_sign_cmd_extra_args --pinentry-mode loopback --passphrase ${{ secrets.GPG_PASSPHRASE }}
  334. EOF
  335. gpg --pinentry-mode loopback --passphrase "${{ secrets.GPG_PASSPHRASE }}" --import <<EOF
  336. ${{ secrets.GPG_KEY }}
  337. EOF
  338. rpmsign --addsign dist/*.rpm
  339. - name: Package Pacman
  340. if: matrix.pacman != ''
  341. run: |-
  342. set -xeuo pipefail
  343. sudo gem install fpm
  344. sudo apt-get update
  345. sudo apt-get install -y libarchive-tools
  346. cp .fpm_systemd .fpm
  347. fpm -t pacman \
  348. -v "$PKG_VERSION" \
  349. -p "dist/sing-box_${{ needs.calculate_version.outputs.version }}_${{ matrix.os }}_${{ matrix.pacman }}.pkg.tar.zst" \
  350. --architecture ${{ matrix.pacman }} \
  351. dist/sing-box=/usr/bin/sing-box
  352. - name: Package OpenWrt
  353. if: matrix.openwrt != ''
  354. run: |-
  355. set -xeuo pipefail
  356. sudo gem install fpm
  357. cp .fpm_openwrt .fpm
  358. fpm -t deb \
  359. -v "$PKG_VERSION" \
  360. -p "dist/openwrt.deb" \
  361. --architecture all \
  362. dist/sing-box=/usr/bin/sing-box
  363. SUFFIX=""
  364. if [[ "${{ matrix.variant }}" == "musl" ]]; then
  365. SUFFIX="_musl"
  366. fi
  367. for architecture in ${{ matrix.openwrt }}; do
  368. .github/deb2ipk.sh "$architecture" "dist/openwrt.deb" "dist/sing-box_${{ needs.calculate_version.outputs.version }}_openwrt_${architecture}${SUFFIX}.ipk"
  369. done
  370. rm "dist/openwrt.deb"
  371. - name: Archive
  372. run: |
  373. set -xeuo pipefail
  374. cd dist
  375. mkdir -p "${DIR_NAME}"
  376. cp ../LICENSE "${DIR_NAME}"
  377. if [ '${{ matrix.os }}' = 'windows' ]; then
  378. cp sing-box "${DIR_NAME}/sing-box.exe"
  379. zip -r "${DIR_NAME}.zip" "${DIR_NAME}"
  380. else
  381. cp sing-box "${DIR_NAME}"
  382. if [ -f libcronet.so ]; then
  383. cp libcronet.so "${DIR_NAME}"
  384. fi
  385. tar -czvf "${DIR_NAME}.tar.gz" "${DIR_NAME}"
  386. fi
  387. rm -r "${DIR_NAME}"
  388. - name: Cleanup
  389. run: rm -f dist/sing-box dist/libcronet.so
  390. - name: Upload artifact
  391. uses: actions/upload-artifact@v4
  392. with:
  393. name: binary-${{ matrix.os }}_${{ matrix.arch }}${{ matrix.goarm && format('v{0}', matrix.goarm) }}${{ matrix.go386 && format('_{0}', matrix.go386) }}${{ matrix.gomips && format('_{0}', matrix.gomips) }}${{ matrix.legacy_name && format('-legacy-{0}', matrix.legacy_name) }}${{ matrix.variant && format('-{0}', matrix.variant) }}
  394. path: "dist"
  395. build_darwin:
  396. name: Build Darwin binaries
  397. if: github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Binary'
  398. runs-on: macos-latest
  399. needs:
  400. - calculate_version
  401. strategy:
  402. matrix:
  403. include:
  404. - { arch: amd64 }
  405. - { arch: arm64 }
  406. - { arch: amd64, legacy_go124: true, legacy_name: "macos-11" }
  407. steps:
  408. - name: Checkout
  409. uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
  410. with:
  411. fetch-depth: 0
  412. - name: Setup Go
  413. if: ${{ ! matrix.legacy_go124 }}
  414. uses: actions/setup-go@v5
  415. with:
  416. go-version: ^1.25.3
  417. - name: Setup Go 1.24
  418. if: matrix.legacy_go124
  419. uses: actions/setup-go@v5
  420. with:
  421. go-version: ~1.24.6
  422. - name: Set tag
  423. run: |-
  424. git ls-remote --exit-code --tags origin v${{ needs.calculate_version.outputs.version }} || echo "PUBLISHED=false" >> "$GITHUB_ENV"
  425. git tag v${{ needs.calculate_version.outputs.version }} -f
  426. - name: Set build tags
  427. run: |
  428. set -xeuo pipefail
  429. 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'
  430. if [[ "${{ matrix.legacy_go124 }}" != "true" ]]; then
  431. TAGS="${TAGS},with_naive_outbound"
  432. fi
  433. echo "BUILD_TAGS=${TAGS}" >> "${GITHUB_ENV}"
  434. - name: Build
  435. run: |
  436. set -xeuo pipefail
  437. mkdir -p dist
  438. go build -v -trimpath -o dist/sing-box -tags "${BUILD_TAGS}" \
  439. -ldflags '-s -buildid= -X github.com/sagernet/sing-box/constant.Version=${{ needs.calculate_version.outputs.version }} -checklinkname=0' \
  440. ./cmd/sing-box
  441. env:
  442. CGO_ENABLED: "1"
  443. GOOS: darwin
  444. GOARCH: ${{ matrix.arch }}
  445. GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  446. - name: Set name
  447. run: |-
  448. DIR_NAME="sing-box-${{ needs.calculate_version.outputs.version }}-darwin-${{ matrix.arch }}"
  449. if [[ -n "${{ matrix.legacy_name }}" ]]; then
  450. DIR_NAME="${DIR_NAME}-legacy-${{ matrix.legacy_name }}"
  451. fi
  452. echo "DIR_NAME=${DIR_NAME}" >> "${GITHUB_ENV}"
  453. - name: Archive
  454. run: |
  455. set -xeuo pipefail
  456. cd dist
  457. mkdir -p "${DIR_NAME}"
  458. cp ../LICENSE "${DIR_NAME}"
  459. cp sing-box "${DIR_NAME}"
  460. tar -czvf "${DIR_NAME}.tar.gz" "${DIR_NAME}"
  461. rm -r "${DIR_NAME}"
  462. - name: Cleanup
  463. run: rm dist/sing-box
  464. - name: Upload artifact
  465. uses: actions/upload-artifact@v4
  466. with:
  467. name: binary-darwin_${{ matrix.arch }}${{ matrix.legacy_name && format('-legacy-{0}', matrix.legacy_name) }}
  468. path: "dist"
  469. build_windows:
  470. name: Build Windows binaries
  471. if: github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Binary'
  472. runs-on: windows-latest
  473. needs:
  474. - calculate_version
  475. strategy:
  476. matrix:
  477. include:
  478. - { arch: amd64, naive: true }
  479. - { arch: "386" }
  480. - { arch: arm64, naive: true }
  481. steps:
  482. - name: Checkout
  483. uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
  484. with:
  485. fetch-depth: 0
  486. - name: Setup Go
  487. uses: actions/setup-go@v5
  488. with:
  489. go-version: ^1.25.4
  490. - name: Set tag
  491. run: |-
  492. git ls-remote --exit-code --tags origin v${{ needs.calculate_version.outputs.version }} || echo "PUBLISHED=false" >> "$env:GITHUB_ENV"
  493. git tag v${{ needs.calculate_version.outputs.version }} -f
  494. - name: Build
  495. if: matrix.naive
  496. run: |
  497. mkdir -p dist
  498. go build -v -trimpath -o dist/sing-box.exe -tags "with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_ocm,with_naive_outbound,with_purego,badlinkname,tfogo_checklinkname0" `
  499. -ldflags "-s -buildid= -X github.com/sagernet/sing-box/constant.Version=${{ needs.calculate_version.outputs.version }} -checklinkname=0" `
  500. ./cmd/sing-box
  501. env:
  502. CGO_ENABLED: "0"
  503. GOOS: windows
  504. GOARCH: ${{ matrix.arch }}
  505. GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  506. - name: Build
  507. if: ${{ !matrix.naive }}
  508. run: |
  509. mkdir -p dist
  510. go build -v -trimpath -o dist/sing-box.exe -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" `
  511. -ldflags "-s -buildid= -X github.com/sagernet/sing-box/constant.Version=${{ needs.calculate_version.outputs.version }} -checklinkname=0" `
  512. ./cmd/sing-box
  513. env:
  514. CGO_ENABLED: "0"
  515. GOOS: windows
  516. GOARCH: ${{ matrix.arch }}
  517. GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  518. - name: Extract libcronet.dll
  519. if: matrix.naive
  520. run: |
  521. $CRONET_GO_VERSION = Get-Content .github/CRONET_GO_VERSION
  522. $env:CGO_ENABLED = "0"
  523. go run -v "github.com/sagernet/cronet-go/cmd/build-naive@$CRONET_GO_VERSION" extract-lib --target windows/${{ matrix.arch }} -o dist
  524. - name: Archive
  525. if: matrix.naive
  526. run: |
  527. $DIR_NAME = "sing-box-${{ needs.calculate_version.outputs.version }}-windows-${{ matrix.arch }}"
  528. mkdir "dist/$DIR_NAME"
  529. Copy-Item LICENSE "dist/$DIR_NAME"
  530. Copy-Item "dist/sing-box.exe" "dist/$DIR_NAME"
  531. Copy-Item "dist/libcronet.dll" "dist/$DIR_NAME"
  532. Compress-Archive -Path "dist/$DIR_NAME" -DestinationPath "dist/$DIR_NAME.zip"
  533. Remove-Item -Recurse "dist/$DIR_NAME"
  534. - name: Archive
  535. if: ${{ !matrix.naive }}
  536. run: |
  537. $DIR_NAME = "sing-box-${{ needs.calculate_version.outputs.version }}-windows-${{ matrix.arch }}"
  538. mkdir "dist/$DIR_NAME"
  539. Copy-Item LICENSE "dist/$DIR_NAME"
  540. Copy-Item "dist/sing-box.exe" "dist/$DIR_NAME"
  541. Compress-Archive -Path "dist/$DIR_NAME" -DestinationPath "dist/$DIR_NAME.zip"
  542. Remove-Item -Recurse "dist/$DIR_NAME"
  543. - name: Cleanup
  544. if: matrix.naive
  545. run: Remove-Item dist/sing-box.exe, dist/libcronet.dll
  546. - name: Cleanup
  547. if: ${{ !matrix.naive }}
  548. run: Remove-Item dist/sing-box.exe
  549. - name: Upload artifact
  550. uses: actions/upload-artifact@v4
  551. with:
  552. name: binary-windows_${{ matrix.arch }}
  553. path: "dist"
  554. build_android:
  555. name: Build Android
  556. if: github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Android'
  557. runs-on: ubuntu-latest
  558. needs:
  559. - calculate_version
  560. steps:
  561. - name: Checkout
  562. uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
  563. with:
  564. fetch-depth: 0
  565. submodules: 'recursive'
  566. - name: Setup Go
  567. uses: actions/setup-go@v5
  568. with:
  569. go-version: ^1.25.5
  570. - name: Setup Android NDK
  571. id: setup-ndk
  572. uses: nttld/setup-ndk@v1
  573. with:
  574. ndk-version: r28
  575. - name: Setup OpenJDK
  576. run: |-
  577. sudo apt update && sudo apt install -y openjdk-17-jdk-headless
  578. /usr/lib/jvm/java-17-openjdk-amd64/bin/java --version
  579. - name: Set tag
  580. run: |-
  581. git ls-remote --exit-code --tags origin v${{ needs.calculate_version.outputs.version }} || echo "PUBLISHED=false" >> "$GITHUB_ENV"
  582. git tag v${{ needs.calculate_version.outputs.version }} -f
  583. - name: Build library
  584. run: |-
  585. make lib_install
  586. export PATH="$PATH:$(go env GOPATH)/bin"
  587. make lib_android
  588. env:
  589. JAVA_HOME: /usr/lib/jvm/java-17-openjdk-amd64
  590. ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
  591. - name: Checkout main branch
  592. if: github.ref == 'refs/heads/main-next' && github.event_name != 'workflow_dispatch'
  593. run: |-
  594. cd clients/android
  595. git checkout main
  596. - name: Checkout dev branch
  597. if: github.ref == 'refs/heads/dev-next'
  598. run: |-
  599. cd clients/android
  600. git checkout dev
  601. - name: Gradle cache
  602. uses: actions/cache@v4
  603. with:
  604. path: ~/.gradle
  605. key: gradle-${{ hashFiles('**/*.gradle') }}
  606. - name: Update version
  607. if: github.event_name == 'workflow_dispatch'
  608. run: |-
  609. go run -v ./cmd/internal/update_android_version --ci
  610. - name: Update nightly version
  611. if: github.event_name != 'workflow_dispatch'
  612. run: |-
  613. go run -v ./cmd/internal/update_android_version --ci --nightly
  614. - name: Build
  615. run: |-
  616. mkdir clients/android/app/libs
  617. cp *.aar clients/android/app/libs
  618. cd clients/android
  619. ./gradlew :app:assembleOtherRelease :app:assembleOtherLegacyRelease
  620. env:
  621. JAVA_HOME: /usr/lib/jvm/java-17-openjdk-amd64
  622. ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
  623. LOCAL_PROPERTIES: ${{ secrets.LOCAL_PROPERTIES }}
  624. - name: Prepare upload
  625. run: |-
  626. mkdir -p dist
  627. #cp clients/android/app/build/outputs/apk/play/release/*.apk dist
  628. cp clients/android/app/build/outputs/apk/other/release/*.apk dist
  629. cp clients/android/app/build/outputs/apk/otherLegacy/release/*.apk dist
  630. VERSION_CODE=$(grep VERSION_CODE clients/android/version.properties | cut -d= -f2)
  631. VERSION_NAME=$(grep VERSION_NAME clients/android/version.properties | cut -d= -f2)
  632. cat > dist/SFA-version-metadata.json << EOF
  633. {
  634. "version_code": ${VERSION_CODE},
  635. "version_name": "${VERSION_NAME}"
  636. }
  637. EOF
  638. cat dist/SFA-version-metadata.json
  639. - name: Upload artifact
  640. uses: actions/upload-artifact@v4
  641. with:
  642. name: binary-android-apks
  643. path: 'dist'
  644. publish_android:
  645. name: Publish Android
  646. if: github.event_name == 'workflow_dispatch' && inputs.build == 'publish-android'
  647. runs-on: ubuntu-latest
  648. needs:
  649. - calculate_version
  650. steps:
  651. - name: Checkout
  652. uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
  653. with:
  654. fetch-depth: 0
  655. submodules: 'recursive'
  656. - name: Setup Go
  657. uses: actions/setup-go@v5
  658. with:
  659. go-version: ^1.25.5
  660. - name: Setup Android NDK
  661. id: setup-ndk
  662. uses: nttld/setup-ndk@v1
  663. with:
  664. ndk-version: r28
  665. - name: Setup OpenJDK
  666. run: |-
  667. sudo apt update && sudo apt install -y openjdk-17-jdk-headless
  668. /usr/lib/jvm/java-17-openjdk-amd64/bin/java --version
  669. - name: Set tag
  670. run: |-
  671. git ls-remote --exit-code --tags origin v${{ needs.calculate_version.outputs.version }} || echo "PUBLISHED=false" >> "$GITHUB_ENV"
  672. git tag v${{ needs.calculate_version.outputs.version }} -f
  673. - name: Build library
  674. run: |-
  675. make lib_install
  676. export PATH="$PATH:$(go env GOPATH)/bin"
  677. make lib_android
  678. env:
  679. JAVA_HOME: /usr/lib/jvm/java-17-openjdk-amd64
  680. ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
  681. - name: Checkout main branch
  682. if: github.ref == 'refs/heads/main-next' && github.event_name != 'workflow_dispatch'
  683. run: |-
  684. cd clients/android
  685. git checkout main
  686. - name: Checkout dev branch
  687. if: github.ref == 'refs/heads/dev-next'
  688. run: |-
  689. cd clients/android
  690. git checkout dev
  691. - name: Gradle cache
  692. uses: actions/cache@v4
  693. with:
  694. path: ~/.gradle
  695. key: gradle-${{ hashFiles('**/*.gradle') }}
  696. - name: Build
  697. run: |-
  698. go run -v ./cmd/internal/update_android_version --ci
  699. mkdir clients/android/app/libs
  700. cp *.aar clients/android/app/libs
  701. cd clients/android
  702. echo -n "$SERVICE_ACCOUNT_CREDENTIALS" | base64 --decode > service-account-credentials.json
  703. ./gradlew :app:publishPlayReleaseBundle
  704. env:
  705. JAVA_HOME: /usr/lib/jvm/java-17-openjdk-amd64
  706. ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
  707. LOCAL_PROPERTIES: ${{ secrets.LOCAL_PROPERTIES }}
  708. SERVICE_ACCOUNT_CREDENTIALS: ${{ secrets.SERVICE_ACCOUNT_CREDENTIALS }}
  709. build_apple:
  710. name: Build Apple clients
  711. runs-on: macos-26
  712. if: false # github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Apple' || inputs.build == 'app-store' || inputs.build == 'iOS' || inputs.build == 'macOS' || inputs.build == 'tvOS' || inputs.build == 'macOS-standalone'
  713. needs:
  714. - calculate_version
  715. strategy:
  716. matrix:
  717. include:
  718. - name: iOS
  719. if: ${{ github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Apple' || inputs.build == 'app-store'|| inputs.build == 'iOS' }}
  720. platform: ios
  721. scheme: SFI
  722. destination: 'generic/platform=iOS'
  723. archive: build/SFI.xcarchive
  724. upload: SFI/Upload.plist
  725. - name: macOS
  726. if: ${{ github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Apple' || inputs.build == 'app-store'|| inputs.build == 'macOS' }}
  727. platform: macos
  728. scheme: SFM
  729. destination: 'generic/platform=macOS'
  730. archive: build/SFM.xcarchive
  731. upload: SFI/Upload.plist
  732. - name: tvOS
  733. if: ${{ github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Apple' || inputs.build == 'app-store'|| inputs.build == 'tvOS' }}
  734. platform: tvos
  735. scheme: SFT
  736. destination: 'generic/platform=tvOS'
  737. archive: build/SFT.xcarchive
  738. upload: SFI/Upload.plist
  739. - name: macOS-standalone
  740. if: ${{ github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Apple' || inputs.build == 'macOS-standalone' }}
  741. platform: macos
  742. scheme: SFM.System
  743. destination: 'generic/platform=macOS'
  744. archive: build/SFM.System.xcarchive
  745. export: SFM.System/Export.plist
  746. export_path: build/SFM.System
  747. steps:
  748. - name: Checkout
  749. if: matrix.if
  750. uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
  751. with:
  752. fetch-depth: 0
  753. submodules: 'recursive'
  754. - name: Setup Go
  755. if: matrix.if
  756. uses: actions/setup-go@v5
  757. with:
  758. go-version: ^1.25.5
  759. - name: Set tag
  760. if: matrix.if
  761. run: |-
  762. git ls-remote --exit-code --tags origin v${{ needs.calculate_version.outputs.version }} || echo "PUBLISHED=false" >> "$GITHUB_ENV"
  763. git tag v${{ needs.calculate_version.outputs.version }} -f
  764. echo "VERSION=${{ needs.calculate_version.outputs.version }}" >> "$GITHUB_ENV"
  765. - name: Checkout main branch
  766. if: matrix.if && github.ref == 'refs/heads/main-next' && github.event_name != 'workflow_dispatch'
  767. run: |-
  768. cd clients/apple
  769. git checkout main
  770. - name: Checkout dev branch
  771. if: matrix.if && github.ref == 'refs/heads/dev-next'
  772. run: |-
  773. cd clients/apple
  774. git checkout dev
  775. - name: Setup certificates
  776. if: matrix.if
  777. run: |-
  778. CERTIFICATE_PATH=$RUNNER_TEMP/Certificates.p12
  779. KEYCHAIN_PATH=$RUNNER_TEMP/certificates.keychain-db
  780. echo -n "$CERTIFICATES_P12" | base64 --decode -o $CERTIFICATE_PATH
  781. security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
  782. security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
  783. security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
  784. security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
  785. security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
  786. security list-keychain -d user -s $KEYCHAIN_PATH
  787. PROFILES_ZIP_PATH=$RUNNER_TEMP/Profiles.zip
  788. echo -n "$PROVISIONING_PROFILES" | base64 --decode -o $PROFILES_ZIP_PATH
  789. PROFILES_PATH="$HOME/Library/MobileDevice/Provisioning Profiles"
  790. mkdir -p "$PROFILES_PATH"
  791. unzip $PROFILES_ZIP_PATH -d "$PROFILES_PATH"
  792. ASC_KEY_PATH=$RUNNER_TEMP/Key.p12
  793. echo -n "$ASC_KEY" | base64 --decode -o $ASC_KEY_PATH
  794. xcrun notarytool store-credentials "notarytool-password" \
  795. --key $ASC_KEY_PATH \
  796. --key-id $ASC_KEY_ID \
  797. --issuer $ASC_KEY_ISSUER_ID
  798. echo "ASC_KEY_PATH=$ASC_KEY_PATH" >> "$GITHUB_ENV"
  799. echo "ASC_KEY_ID=$ASC_KEY_ID" >> "$GITHUB_ENV"
  800. echo "ASC_KEY_ISSUER_ID=$ASC_KEY_ISSUER_ID" >> "$GITHUB_ENV"
  801. env:
  802. CERTIFICATES_P12: ${{ secrets.CERTIFICATES_P12 }}
  803. P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
  804. KEYCHAIN_PASSWORD: ${{ secrets.P12_PASSWORD }}
  805. PROVISIONING_PROFILES: ${{ secrets.PROVISIONING_PROFILES }}
  806. ASC_KEY: ${{ secrets.ASC_KEY }}
  807. ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
  808. ASC_KEY_ISSUER_ID: ${{ secrets.ASC_KEY_ISSUER_ID }}
  809. - name: Build library
  810. if: matrix.if
  811. run: |-
  812. make lib_install
  813. export PATH="$PATH:$(go env GOPATH)/bin"
  814. go run ./cmd/internal/build_libbox -target apple -platform ${{ matrix.platform }}
  815. mv Libbox.xcframework clients/apple
  816. - name: Update macOS version
  817. if: matrix.if && matrix.name == 'macOS' && github.event_name == 'workflow_dispatch'
  818. run: |-
  819. MACOS_PROJECT_VERSION=$(go run -v ./cmd/internal/app_store_connect next_macos_project_version)
  820. echo "MACOS_PROJECT_VERSION=$MACOS_PROJECT_VERSION"
  821. echo "MACOS_PROJECT_VERSION=$MACOS_PROJECT_VERSION" >> "$GITHUB_ENV"
  822. - name: Update version
  823. if: matrix.if && matrix.name != 'iOS'
  824. run: |-
  825. go run -v ./cmd/internal/update_apple_version --ci
  826. - name: Build
  827. if: matrix.if
  828. run: |-
  829. cd clients/apple
  830. xcodebuild archive \
  831. -scheme "${{ matrix.scheme }}" \
  832. -configuration Release \
  833. -destination "${{ matrix.destination }}" \
  834. -archivePath "${{ matrix.archive }}" \
  835. -allowProvisioningUpdates \
  836. -authenticationKeyPath $ASC_KEY_PATH \
  837. -authenticationKeyID $ASC_KEY_ID \
  838. -authenticationKeyIssuerID $ASC_KEY_ISSUER_ID
  839. - name: Upload to App Store Connect
  840. if: matrix.if && matrix.name != 'macOS-standalone' && github.event_name == 'workflow_dispatch'
  841. run: |-
  842. go run -v ./cmd/internal/app_store_connect cancel_app_store ${{ matrix.platform }}
  843. cd clients/apple
  844. xcodebuild -exportArchive \
  845. -archivePath "${{ matrix.archive }}" \
  846. -exportOptionsPlist ${{ matrix.upload }} \
  847. -allowProvisioningUpdates \
  848. -authenticationKeyPath $ASC_KEY_PATH \
  849. -authenticationKeyID $ASC_KEY_ID \
  850. -authenticationKeyIssuerID $ASC_KEY_ISSUER_ID
  851. - name: Publish to TestFlight
  852. if: matrix.if && matrix.name != 'macOS-standalone' && github.event_name == 'workflow_dispatch' && github.ref =='refs/heads/dev-next'
  853. run: |-
  854. go run -v ./cmd/internal/app_store_connect publish_testflight ${{ matrix.platform }}
  855. - name: Build image
  856. if: matrix.if && matrix.name == 'macOS-standalone' && github.event_name == 'workflow_dispatch'
  857. run: |-
  858. pushd clients/apple
  859. xcodebuild -exportArchive \
  860. -archivePath "${{ matrix.archive }}" \
  861. -exportOptionsPlist ${{ matrix.export }} \
  862. -exportPath "${{ matrix.export_path }}"
  863. brew install create-dmg
  864. create-dmg \
  865. --volname "sing-box" \
  866. --volicon "${{ matrix.export_path }}/SFM.app/Contents/Resources/AppIcon.icns" \
  867. --icon "SFM.app" 0 0 \
  868. --hide-extension "SFM.app" \
  869. --app-drop-link 0 0 \
  870. --skip-jenkins \
  871. SFM.dmg "${{ matrix.export_path }}/SFM.app"
  872. xcrun notarytool submit "SFM.dmg" --wait --keychain-profile "notarytool-password"
  873. cd "${{ matrix.archive }}"
  874. zip -r SFM.dSYMs.zip dSYMs
  875. popd
  876. mkdir -p dist
  877. cp clients/apple/SFM.dmg "dist/SFM-${VERSION}-universal.dmg"
  878. cp "clients/apple/${{ matrix.archive }}/SFM.dSYMs.zip" "dist/SFM-${VERSION}-universal.dSYMs.zip"
  879. - name: Upload image
  880. if: matrix.if && matrix.name == 'macOS-standalone' && github.event_name == 'workflow_dispatch'
  881. uses: actions/upload-artifact@v4
  882. with:
  883. name: binary-macos-dmg
  884. path: 'dist'
  885. upload:
  886. name: Upload builds
  887. if: "!failure() && github.event_name == 'workflow_dispatch' && (inputs.build == 'All' || inputs.build == 'Binary' || inputs.build == 'Android' || inputs.build == 'Apple' || inputs.build == 'macOS-standalone')"
  888. runs-on: ubuntu-latest
  889. needs:
  890. - calculate_version
  891. - build
  892. - build_darwin
  893. - build_windows
  894. - build_android
  895. - build_apple
  896. steps:
  897. - name: Checkout
  898. uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
  899. with:
  900. fetch-depth: 0
  901. - name: Cache ghr
  902. uses: actions/cache@v4
  903. id: cache-ghr
  904. with:
  905. path: |
  906. ~/go/bin/ghr
  907. key: ghr
  908. - name: Setup ghr
  909. if: steps.cache-ghr.outputs.cache-hit != 'true'
  910. run: |-
  911. cd $HOME
  912. git clone https://github.com/nekohasekai/ghr ghr
  913. cd ghr
  914. go install -v .
  915. - name: Set tag
  916. run: |-
  917. git ls-remote --exit-code --tags origin v${{ needs.calculate_version.outputs.version }} || echo "PUBLISHED=false" >> "$GITHUB_ENV"
  918. git tag v${{ needs.calculate_version.outputs.version }} -f
  919. echo "VERSION=${{ needs.calculate_version.outputs.version }}" >> "$GITHUB_ENV"
  920. - name: Download builds
  921. uses: actions/download-artifact@v5
  922. with:
  923. path: dist
  924. merge-multiple: true
  925. - name: Upload builds
  926. if: ${{ env.PUBLISHED == 'false' }}
  927. run: |-
  928. export PATH="$PATH:$HOME/go/bin"
  929. ghr --replace --draft --prerelease -p 5 "v${VERSION}" dist
  930. env:
  931. GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  932. - name: Replace builds
  933. if: ${{ env.PUBLISHED != 'false' }}
  934. run: |-
  935. export PATH="$PATH:$HOME/go/bin"
  936. ghr --replace -p 5 "v${VERSION}" dist
  937. env:
  938. GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}