| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666 |
- name: Build
- on:
- workflow_dispatch:
- inputs:
- version:
- description: "Version name"
- required: true
- type: string
- build:
- description: "Build type"
- required: true
- type: choice
- default: "All"
- options:
- - All
- - Binary
- - Android
- - Apple
- - app-store
- - iOS
- - macOS
- - tvOS
- - macOS-standalone
- - publish-android
- push:
- branches:
- - main-next
- - dev-next
- concurrency:
- group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}-${{ inputs.build }}
- cancel-in-progress: true
- jobs:
- calculate_version:
- name: Calculate version
- runs-on: ubuntu-latest
- outputs:
- version: ${{ steps.outputs.outputs.version }}
- steps:
- - name: Checkout
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
- with:
- fetch-depth: 0
- - name: Setup Go
- uses: actions/setup-go@v5
- with:
- go-version: ^1.25.3
- - name: Check input version
- if: github.event_name == 'workflow_dispatch'
- run: |-
- echo "version=${{ inputs.version }}"
- echo "version=${{ inputs.version }}" >> "$GITHUB_ENV"
- - name: Calculate version
- if: github.event_name != 'workflow_dispatch'
- run: |-
- go run -v ./cmd/internal/read_tag --ci --nightly
- - name: Set outputs
- id: outputs
- run: |-
- echo "version=$version" >> "$GITHUB_OUTPUT"
- build:
- name: Build binary
- if: github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Binary'
- runs-on: ubuntu-latest
- needs:
- - calculate_version
- strategy:
- matrix:
- include:
- - { os: linux, arch: amd64, debian: amd64, rpm: x86_64, pacman: x86_64, openwrt: "x86_64" }
- - { os: linux, arch: "386", go386: sse2, debian: i386, rpm: i386, openwrt: "i386_pentium4" }
- - { os: linux, arch: "386", go386: softfloat, openwrt: "i386_pentium-mmx" }
- - { os: linux, arch: arm64, debian: arm64, rpm: aarch64, pacman: aarch64, openwrt: "aarch64_cortex-a53 aarch64_cortex-a72 aarch64_cortex-a76 aarch64_generic" }
- - { os: linux, arch: arm, goarm: "5", openwrt: "arm_arm926ej-s arm_cortex-a7 arm_cortex-a9 arm_fa526 arm_xscale" }
- - { os: linux, arch: arm, goarm: "6", debian: armel, rpm: armv6hl, openwrt: "arm_arm1176jzf-s_vfp" }
- - { os: linux, arch: arm, 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" }
- - { os: linux, arch: mips, gomips: softfloat, openwrt: "mips_24kc mips_4kec mips_mips32" }
- - { os: linux, arch: mipsle, gomips: hardfloat, debian: mipsel, rpm: mipsel, openwrt: "mipsel_24kc_24kf" }
- - { os: linux, arch: mipsle, gomips: softfloat, openwrt: "mipsel_24kc mipsel_74kc mipsel_mips32" }
- - { os: linux, arch: mips64, gomips: softfloat, openwrt: "mips64_mips64r2 mips64_octeonplus" }
- - { os: linux, arch: mips64le, gomips: hardfloat, debian: mips64el, rpm: mips64el }
- - { os: linux, arch: mips64le, gomips: softfloat, openwrt: "mips64el_mips64r2" }
- - { os: linux, arch: s390x, debian: s390x, rpm: s390x }
- - { os: linux, arch: ppc64le, debian: ppc64el, rpm: ppc64le }
- - { os: linux, arch: riscv64, debian: riscv64, rpm: riscv64, openwrt: "riscv64_generic" }
- - { os: linux, arch: loong64, debian: loongarch64, rpm: loongarch64, openwrt: "loongarch64_generic" }
- - { os: windows, arch: amd64 }
- - { os: windows, arch: amd64, legacy_win7: true, legacy_name: "windows-7" }
- - { os: windows, arch: "386" }
- - { os: windows, arch: "386", legacy_win7: true, legacy_name: "windows-7" }
- - { os: windows, arch: arm64 }
- - { os: darwin, arch: amd64 }
- - { os: darwin, arch: arm64 }
- - { os: darwin, arch: amd64, legacy_go124: true, legacy_name: "macos-11" }
- - { os: android, arch: arm64, ndk: "aarch64-linux-android21" }
- - { os: android, arch: arm, ndk: "armv7a-linux-androideabi21" }
- - { os: android, arch: amd64, ndk: "x86_64-linux-android21" }
- - { os: android, arch: "386", ndk: "i686-linux-android21" }
- steps:
- - name: Checkout
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
- with:
- fetch-depth: 0
- - name: Setup Go
- if: ${{ ! (matrix.legacy_go123 || matrix.legacy_go124) }}
- uses: actions/setup-go@v5
- with:
- go-version: ^1.25.3
- - name: Setup Go 1.24
- if: matrix.legacy_go124
- uses: actions/setup-go@v5
- with:
- go-version: ~1.24.6
- - name: Cache Go for Windows 7
- if: matrix.legacy_win7
- id: cache-go-for-windows7
- uses: actions/cache@v4
- with:
- path: |
- ~/go/go_win7
- key: go_win7_1253
- - name: Setup Go for Windows 7
- if: matrix.legacy_win7 && steps.cache-go-for-windows7.outputs.cache-hit != 'true'
- run: |-
- .github/setup_go_for_windows7.sh
- - name: Setup Go for Windows 7
- if: matrix.legacy_win7
- run: |-
- echo "PATH=$HOME/go/go_win7/bin:$PATH" >> $GITHUB_ENV
- echo "GOROOT=$HOME/go/go_win7" >> $GITHUB_ENV
- - name: Setup Android NDK
- if: matrix.os == 'android'
- uses: nttld/setup-ndk@v1
- with:
- ndk-version: r28
- local-cache: true
- - name: Set tag
- run: |-
- git ls-remote --exit-code --tags origin v${{ needs.calculate_version.outputs.version }} || echo "PUBLISHED=false" >> "$GITHUB_ENV"
- git tag v${{ needs.calculate_version.outputs.version }} -f
- - name: Set build tags
- run: |
- set -xeuo pipefail
- TAGS='with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale'
- echo "BUILD_TAGS=${TAGS}" >> "${GITHUB_ENV}"
- - name: Build
- if: matrix.os != 'android'
- run: |
- set -xeuo pipefail
- mkdir -p dist
- go build -v -trimpath -o dist/sing-box -tags "${BUILD_TAGS}" \
- -ldflags '-s -buildid= -X github.com/sagernet/sing-box/constant.Version=${{ needs.calculate_version.outputs.version }}' \
- ./cmd/sing-box
- env:
- CGO_ENABLED: "0"
- GOOS: ${{ matrix.os }}
- GOARCH: ${{ matrix.arch }}
- GO386: ${{ matrix.go386 }}
- GOARM: ${{ matrix.goarm }}
- GOMIPS: ${{ matrix.gomips }}
- GOMIPS64: ${{ matrix.gomips }}
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- - name: Build Android
- if: matrix.os == 'android'
- run: |
- set -xeuo pipefail
- go install -v ./cmd/internal/build
- export CC='${{ matrix.ndk }}-clang'
- export CXX="${CC}++"
- mkdir -p dist
- GOOS=$BUILD_GOOS GOARCH=$BUILD_GOARCH build go build -v -trimpath -o dist/sing-box -tags "${BUILD_TAGS}" \
- -ldflags '-s -buildid= -X github.com/sagernet/sing-box/constant.Version=${{ needs.calculate_version.outputs.version }}' \
- ./cmd/sing-box
- env:
- CGO_ENABLED: "1"
- BUILD_GOOS: ${{ matrix.os }}
- BUILD_GOARCH: ${{ matrix.arch }}
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- - name: Set name
- run: |-
- DIR_NAME="sing-box-${{ needs.calculate_version.outputs.version }}-${{ matrix.os }}-${{ matrix.arch }}"
- if [[ -n "${{ matrix.goarm }}" ]]; then
- DIR_NAME="${DIR_NAME}v${{ matrix.goarm }}"
- elif [[ -n "${{ matrix.go386 }}" && "${{ matrix.go386 }}" != 'sse2' ]]; then
- DIR_NAME="${DIR_NAME}-${{ matrix.go386 }}"
- elif [[ -n "${{ matrix.gomips }}" && "${{ matrix.gomips }}" != 'hardfloat' ]]; then
- DIR_NAME="${DIR_NAME}-${{ matrix.gomips }}"
- elif [[ -n "${{ matrix.legacy_name }}" ]]; then
- DIR_NAME="${DIR_NAME}-legacy-${{ matrix.legacy_name }}"
- fi
- echo "DIR_NAME=${DIR_NAME}" >> "${GITHUB_ENV}"
- PKG_VERSION="${{ needs.calculate_version.outputs.version }}"
- PKG_VERSION="${PKG_VERSION//-/\~}"
- echo "PKG_VERSION=${PKG_VERSION}" >> "${GITHUB_ENV}"
- - name: Package DEB
- if: matrix.debian != ''
- run: |
- set -xeuo pipefail
- sudo gem install fpm
- sudo apt-get update
- sudo apt-get install -y debsigs
- cp .fpm_systemd .fpm
- fpm -t deb \
- -v "$PKG_VERSION" \
- -p "dist/sing-box_${{ needs.calculate_version.outputs.version }}_${{ matrix.os }}_${{ matrix.debian }}.deb" \
- --architecture ${{ matrix.debian }} \
- dist/sing-box=/usr/bin/sing-box
- curl -Lo '/tmp/debsigs.diff' 'https://gitlab.com/debsigs/debsigs/-/commit/160138f5de1ec110376d3c807b60a37388bc7c90.diff'
- sudo patch /usr/bin/debsigs < '/tmp/debsigs.diff'
- rm -rf $HOME/.gnupg
- gpg --pinentry-mode loopback --passphrase "${{ secrets.GPG_PASSPHRASE }}" --import <<EOF
- ${{ secrets.GPG_KEY }}
- EOF
- debsigs --sign=origin -k ${{ secrets.GPG_KEY_ID }} --gpgopts '--pinentry-mode loopback --passphrase "${{ secrets.GPG_PASSPHRASE }}"' dist/*.deb
- - name: Package RPM
- if: matrix.rpm != ''
- run: |-
- set -xeuo pipefail
- sudo gem install fpm
- cp .fpm_systemd .fpm
- fpm -t rpm \
- -v "$PKG_VERSION" \
- -p "dist/sing-box_${{ needs.calculate_version.outputs.version }}_${{ matrix.os }}_${{ matrix.rpm }}.rpm" \
- --architecture ${{ matrix.rpm }} \
- dist/sing-box=/usr/bin/sing-box
- cat > $HOME/.rpmmacros <<EOF
- %_gpg_name ${{ secrets.GPG_KEY_ID }}
- %_gpg_sign_cmd_extra_args --pinentry-mode loopback --passphrase ${{ secrets.GPG_PASSPHRASE }}
- EOF
- gpg --pinentry-mode loopback --passphrase "${{ secrets.GPG_PASSPHRASE }}" --import <<EOF
- ${{ secrets.GPG_KEY }}
- EOF
- rpmsign --addsign dist/*.rpm
- - name: Package Pacman
- if: matrix.pacman != ''
- run: |-
- set -xeuo pipefail
- sudo gem install fpm
- sudo apt-get update
- sudo apt-get install -y libarchive-tools
- cp .fpm_systemd .fpm
- fpm -t pacman \
- -v "$PKG_VERSION" \
- -p "dist/sing-box_${{ needs.calculate_version.outputs.version }}_${{ matrix.os }}_${{ matrix.pacman }}.pkg.tar.zst" \
- --architecture ${{ matrix.pacman }} \
- dist/sing-box=/usr/bin/sing-box
- - name: Package OpenWrt
- if: matrix.openwrt != ''
- run: |-
- set -xeuo pipefail
- sudo gem install fpm
- cp .fpm_openwrt .fpm
- fpm -t deb \
- -v "$PKG_VERSION" \
- -p "dist/openwrt.deb" \
- --architecture all \
- dist/sing-box=/usr/bin/sing-box
- for architecture in ${{ matrix.openwrt }}; do
- .github/deb2ipk.sh "$architecture" "dist/openwrt.deb" "dist/sing-box_${{ needs.calculate_version.outputs.version }}_openwrt_${architecture}.ipk"
- done
- rm "dist/openwrt.deb"
- - name: Archive
- run: |
- set -xeuo pipefail
- cd dist
- mkdir -p "${DIR_NAME}"
- cp ../LICENSE "${DIR_NAME}"
- if [ '${{ matrix.os }}' = 'windows' ]; then
- cp sing-box "${DIR_NAME}/sing-box.exe"
- zip -r "${DIR_NAME}.zip" "${DIR_NAME}"
- else
- cp sing-box "${DIR_NAME}"
- tar -czvf "${DIR_NAME}.tar.gz" "${DIR_NAME}"
- fi
- rm -r "${DIR_NAME}"
- - name: Cleanup
- run: rm dist/sing-box
- - name: Upload artifact
- uses: actions/upload-artifact@v4
- with:
- 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) }}
- path: "dist"
- build_android:
- name: Build Android
- if: github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Android'
- runs-on: ubuntu-latest
- needs:
- - calculate_version
- steps:
- - name: Checkout
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
- with:
- fetch-depth: 0
- submodules: 'recursive'
- - name: Setup Go
- uses: actions/setup-go@v5
- with:
- go-version: ^1.25.3
- - name: Setup Android NDK
- id: setup-ndk
- uses: nttld/setup-ndk@v1
- with:
- ndk-version: r28
- - name: Setup OpenJDK
- run: |-
- sudo apt update && sudo apt install -y openjdk-17-jdk-headless
- /usr/lib/jvm/java-17-openjdk-amd64/bin/java --version
- - name: Set tag
- run: |-
- git ls-remote --exit-code --tags origin v${{ needs.calculate_version.outputs.version }} || echo "PUBLISHED=false" >> "$GITHUB_ENV"
- git tag v${{ needs.calculate_version.outputs.version }} -f
- - name: Build library
- run: |-
- make lib_install
- export PATH="$PATH:$(go env GOPATH)/bin"
- make lib_android
- env:
- JAVA_HOME: /usr/lib/jvm/java-17-openjdk-amd64
- ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
- - name: Checkout main branch
- if: github.ref == 'refs/heads/main-next' && github.event_name != 'workflow_dispatch'
- run: |-
- cd clients/android
- git checkout main
- - name: Checkout dev branch
- if: github.ref == 'refs/heads/dev-next'
- run: |-
- cd clients/android
- git checkout dev
- - name: Gradle cache
- uses: actions/cache@v4
- with:
- path: ~/.gradle
- key: gradle-${{ hashFiles('**/*.gradle') }}
- - name: Update version
- if: github.event_name == 'workflow_dispatch'
- run: |-
- go run -v ./cmd/internal/update_android_version --ci
- - name: Update nightly version
- if: github.event_name != 'workflow_dispatch'
- run: |-
- go run -v ./cmd/internal/update_android_version --ci --nightly
- - name: Build
- run: |-
- mkdir clients/android/app/libs
- cp libbox.aar clients/android/app/libs
- cd clients/android
- ./gradlew :app:assemblePlayRelease :app:assembleOtherRelease
- env:
- JAVA_HOME: /usr/lib/jvm/java-17-openjdk-amd64
- ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
- LOCAL_PROPERTIES: ${{ secrets.LOCAL_PROPERTIES }}
- - name: Prepare upload
- run: |-
- mkdir -p dist
- cp clients/android/app/build/outputs/apk/play/release/*.apk dist
- cp clients/android/app/build/outputs/apk/other/release/*-universal.apk dist
- - name: Upload artifact
- uses: actions/upload-artifact@v4
- with:
- name: binary-android-apks
- path: 'dist'
- publish_android:
- name: Publish Android
- if: github.event_name == 'workflow_dispatch' && inputs.build == 'publish-android'
- runs-on: ubuntu-latest
- needs:
- - calculate_version
- steps:
- - name: Checkout
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
- with:
- fetch-depth: 0
- submodules: 'recursive'
- - name: Setup Go
- uses: actions/setup-go@v5
- with:
- go-version: ^1.25.3
- - name: Setup Android NDK
- id: setup-ndk
- uses: nttld/setup-ndk@v1
- with:
- ndk-version: r28
- - name: Setup OpenJDK
- run: |-
- sudo apt update && sudo apt install -y openjdk-17-jdk-headless
- /usr/lib/jvm/java-17-openjdk-amd64/bin/java --version
- - name: Set tag
- run: |-
- git ls-remote --exit-code --tags origin v${{ needs.calculate_version.outputs.version }} || echo "PUBLISHED=false" >> "$GITHUB_ENV"
- git tag v${{ needs.calculate_version.outputs.version }} -f
- - name: Build library
- run: |-
- make lib_install
- export PATH="$PATH:$(go env GOPATH)/bin"
- make lib_android
- env:
- JAVA_HOME: /usr/lib/jvm/java-17-openjdk-amd64
- ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
- - name: Checkout main branch
- if: github.ref == 'refs/heads/main-next' && github.event_name != 'workflow_dispatch'
- run: |-
- cd clients/android
- git checkout main
- - name: Checkout dev branch
- if: github.ref == 'refs/heads/dev-next'
- run: |-
- cd clients/android
- git checkout dev
- - name: Gradle cache
- uses: actions/cache@v4
- with:
- path: ~/.gradle
- key: gradle-${{ hashFiles('**/*.gradle') }}
- - name: Build
- run: |-
- go run -v ./cmd/internal/update_android_version --ci
- mkdir clients/android/app/libs
- cp libbox.aar clients/android/app/libs
- cd clients/android
- echo -n "$SERVICE_ACCOUNT_CREDENTIALS" | base64 --decode > service-account-credentials.json
- ./gradlew :app:publishPlayReleaseBundle
- env:
- JAVA_HOME: /usr/lib/jvm/java-17-openjdk-amd64
- ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
- LOCAL_PROPERTIES: ${{ secrets.LOCAL_PROPERTIES }}
- SERVICE_ACCOUNT_CREDENTIALS: ${{ secrets.SERVICE_ACCOUNT_CREDENTIALS }}
- build_apple:
- name: Build Apple clients
- runs-on: macos-26
- if: false
- needs:
- - calculate_version
- strategy:
- matrix:
- include:
- - name: iOS
- if: ${{ github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Apple' || inputs.build == 'app-store'|| inputs.build == 'iOS' }}
- platform: ios
- scheme: SFI
- destination: 'generic/platform=iOS'
- archive: build/SFI.xcarchive
- upload: SFI/Upload.plist
- - name: macOS
- if: ${{ github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Apple' || inputs.build == 'app-store'|| inputs.build == 'macOS' }}
- platform: macos
- scheme: SFM
- destination: 'generic/platform=macOS'
- archive: build/SFM.xcarchive
- upload: SFI/Upload.plist
- - name: tvOS
- if: ${{ github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Apple' || inputs.build == 'app-store'|| inputs.build == 'tvOS' }}
- platform: tvos
- scheme: SFT
- destination: 'generic/platform=tvOS'
- archive: build/SFT.xcarchive
- upload: SFI/Upload.plist
- - name: macOS-standalone
- if: ${{ github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Apple' || inputs.build == 'macOS-standalone' }}
- platform: macos
- scheme: SFM.System
- destination: 'generic/platform=macOS'
- archive: build/SFM.System.xcarchive
- export: SFM.System/Export.plist
- export_path: build/SFM.System
- steps:
- - name: Checkout
- if: matrix.if
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
- with:
- fetch-depth: 0
- submodules: 'recursive'
- - name: Setup Go
- if: matrix.if
- uses: actions/setup-go@v5
- with:
- go-version: ^1.25.3
- - name: Set tag
- if: matrix.if
- run: |-
- git ls-remote --exit-code --tags origin v${{ needs.calculate_version.outputs.version }} || echo "PUBLISHED=false" >> "$GITHUB_ENV"
- git tag v${{ needs.calculate_version.outputs.version }} -f
- echo "VERSION=${{ needs.calculate_version.outputs.version }}" >> "$GITHUB_ENV"
- - name: Checkout main branch
- if: matrix.if && github.ref == 'refs/heads/main-next' && github.event_name != 'workflow_dispatch'
- run: |-
- cd clients/apple
- git checkout main
- - name: Checkout dev branch
- if: matrix.if && github.ref == 'refs/heads/dev-next'
- run: |-
- cd clients/apple
- git checkout dev
- - name: Setup certificates
- if: matrix.if
- run: |-
- CERTIFICATE_PATH=$RUNNER_TEMP/Certificates.p12
- KEYCHAIN_PATH=$RUNNER_TEMP/certificates.keychain-db
- echo -n "$CERTIFICATES_P12" | base64 --decode -o $CERTIFICATE_PATH
- security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
- security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
- security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
- security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
- security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
- security list-keychain -d user -s $KEYCHAIN_PATH
- PROFILES_ZIP_PATH=$RUNNER_TEMP/Profiles.zip
- echo -n "$PROVISIONING_PROFILES" | base64 --decode -o $PROFILES_ZIP_PATH
- PROFILES_PATH="$HOME/Library/MobileDevice/Provisioning Profiles"
- mkdir -p "$PROFILES_PATH"
- unzip $PROFILES_ZIP_PATH -d "$PROFILES_PATH"
- ASC_KEY_PATH=$RUNNER_TEMP/Key.p12
- echo -n "$ASC_KEY" | base64 --decode -o $ASC_KEY_PATH
- xcrun notarytool store-credentials "notarytool-password" \
- --key $ASC_KEY_PATH \
- --key-id $ASC_KEY_ID \
- --issuer $ASC_KEY_ISSUER_ID
- echo "ASC_KEY_PATH=$ASC_KEY_PATH" >> "$GITHUB_ENV"
- echo "ASC_KEY_ID=$ASC_KEY_ID" >> "$GITHUB_ENV"
- echo "ASC_KEY_ISSUER_ID=$ASC_KEY_ISSUER_ID" >> "$GITHUB_ENV"
- env:
- CERTIFICATES_P12: ${{ secrets.CERTIFICATES_P12 }}
- P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
- KEYCHAIN_PASSWORD: ${{ secrets.P12_PASSWORD }}
- PROVISIONING_PROFILES: ${{ secrets.PROVISIONING_PROFILES }}
- ASC_KEY: ${{ secrets.ASC_KEY }}
- ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
- ASC_KEY_ISSUER_ID: ${{ secrets.ASC_KEY_ISSUER_ID }}
- - name: Build library
- if: matrix.if
- run: |-
- make lib_install
- export PATH="$PATH:$(go env GOPATH)/bin"
- go run ./cmd/internal/build_libbox -target apple -platform ${{ matrix.platform }}
- mv Libbox.xcframework clients/apple
- - name: Update macOS version
- if: matrix.if && matrix.name == 'macOS' && github.event_name == 'workflow_dispatch'
- run: |-
- MACOS_PROJECT_VERSION=$(go run -v ./cmd/internal/app_store_connect next_macos_project_version)
- echo "MACOS_PROJECT_VERSION=$MACOS_PROJECT_VERSION"
- echo "MACOS_PROJECT_VERSION=$MACOS_PROJECT_VERSION" >> "$GITHUB_ENV"
- - name: Update version
- if: matrix.if && matrix.name != 'iOS'
- run: |-
- go run -v ./cmd/internal/update_apple_version --ci
- - name: Build
- if: matrix.if
- run: |-
- cd clients/apple
- xcodebuild archive \
- -scheme "${{ matrix.scheme }}" \
- -configuration Release \
- -destination "${{ matrix.destination }}" \
- -archivePath "${{ matrix.archive }}" \
- -allowProvisioningUpdates \
- -authenticationKeyPath $ASC_KEY_PATH \
- -authenticationKeyID $ASC_KEY_ID \
- -authenticationKeyIssuerID $ASC_KEY_ISSUER_ID
- - name: Upload to App Store Connect
- if: matrix.if && matrix.name != 'macOS-standalone' && github.event_name == 'workflow_dispatch'
- run: |-
- go run -v ./cmd/internal/app_store_connect cancel_app_store ${{ matrix.platform }}
- cd clients/apple
- xcodebuild -exportArchive \
- -archivePath "${{ matrix.archive }}" \
- -exportOptionsPlist ${{ matrix.upload }} \
- -allowProvisioningUpdates \
- -authenticationKeyPath $ASC_KEY_PATH \
- -authenticationKeyID $ASC_KEY_ID \
- -authenticationKeyIssuerID $ASC_KEY_ISSUER_ID
- - name: Publish to TestFlight
- if: matrix.if && matrix.name != 'macOS-standalone' && github.event_name == 'workflow_dispatch' && github.ref =='refs/heads/dev-next'
- run: |-
- go run -v ./cmd/internal/app_store_connect publish_testflight ${{ matrix.platform }}
- - name: Build image
- if: matrix.if && matrix.name == 'macOS-standalone' && github.event_name == 'workflow_dispatch'
- run: |-
- pushd clients/apple
- xcodebuild -exportArchive \
- -archivePath "${{ matrix.archive }}" \
- -exportOptionsPlist ${{ matrix.export }} \
- -exportPath "${{ matrix.export_path }}"
- brew install create-dmg
- create-dmg \
- --volname "sing-box" \
- --volicon "${{ matrix.export_path }}/SFM.app/Contents/Resources/AppIcon.icns" \
- --icon "SFM.app" 0 0 \
- --hide-extension "SFM.app" \
- --app-drop-link 0 0 \
- --skip-jenkins \
- SFM.dmg "${{ matrix.export_path }}/SFM.app"
- xcrun notarytool submit "SFM.dmg" --wait --keychain-profile "notarytool-password"
- cd "${{ matrix.archive }}"
- zip -r SFM.dSYMs.zip dSYMs
- popd
- mkdir -p dist
- cp clients/apple/SFM.dmg "dist/SFM-${VERSION}-universal.dmg"
- cp "clients/apple/${{ matrix.archive }}/SFM.dSYMs.zip" "dist/SFM-${VERSION}-universal.dSYMs.zip"
- - name: Upload image
- if: matrix.if && matrix.name == 'macOS-standalone' && github.event_name == 'workflow_dispatch'
- uses: actions/upload-artifact@v4
- with:
- name: binary-macos-dmg
- path: 'dist'
- upload:
- name: Upload builds
- if: "!failure() && github.event_name == 'workflow_dispatch' && (inputs.build == 'All' || inputs.build == 'Binary' || inputs.build == 'Android' || inputs.build == 'Apple' || inputs.build == 'macOS-standalone')"
- runs-on: ubuntu-latest
- needs:
- - calculate_version
- - build
- - build_android
- - build_apple
- steps:
- - name: Checkout
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
- with:
- fetch-depth: 0
- - name: Cache ghr
- uses: actions/cache@v4
- id: cache-ghr
- with:
- path: |
- ~/go/bin/ghr
- key: ghr
- - name: Setup ghr
- if: steps.cache-ghr.outputs.cache-hit != 'true'
- run: |-
- cd $HOME
- git clone https://github.com/nekohasekai/ghr ghr
- cd ghr
- go install -v .
- - name: Set tag
- run: |-
- git ls-remote --exit-code --tags origin v${{ needs.calculate_version.outputs.version }} || echo "PUBLISHED=false" >> "$GITHUB_ENV"
- git tag v${{ needs.calculate_version.outputs.version }} -f
- echo "VERSION=${{ needs.calculate_version.outputs.version }}" >> "$GITHUB_ENV"
- - name: Download builds
- uses: actions/download-artifact@v5
- with:
- path: dist
- merge-multiple: true
- - name: Upload builds
- if: ${{ env.PUBLISHED == 'false' }}
- run: |-
- export PATH="$PATH:$HOME/go/bin"
- ghr --replace --draft --prerelease -p 5 "v${VERSION}" dist
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- - name: Replace builds
- if: ${{ env.PUBLISHED != 'false' }}
- run: |-
- export PATH="$PATH:$HOME/go/bin"
- ghr --replace -p 5 "v${VERSION}" dist
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|