diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b55a331a..403f7e1c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,10 +28,6 @@ on: - tvOS - macOS-standalone - publish-android - macos_project_version: - description: "macOS project version" - required: false - type: string push: branches: - main-next @@ -354,67 +350,38 @@ jobs: ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} LOCAL_PROPERTIES: ${{ secrets.LOCAL_PROPERTIES }} SERVICE_ACCOUNT_CREDENTIALS: ${{ secrets.SERVICE_ACCOUNT_CREDENTIALS }} - build_apple_library: - name: Build Apple library - if: 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' - runs-on: macos-15 - needs: - - calculate_version - steps: - - name: Checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4 - with: - fetch-depth: 0 - submodules: 'recursive' - - name: Setup Go - uses: actions/setup-go@v5 - with: - go-version: ^1.23 - - name: Setup Xcode - run: |- - sudo xcode-select -s /Applications/Xcode_16.2_beta_3.app - - name: Set tag - run: |- - git tag v${{ needs.calculate_version.outputs.version }} - - name: Build library - run: |- - make lib_install - export PATH="$PATH:$(go env GOPATH)/bin" - make lib_ios - - name: Upload library - uses: actions/upload-artifact@v4 - with: - name: library-apple - path: 'Libbox.xcframework' build_apple: name: Build Apple clients runs-on: macos-15 needs: - calculate_version - - build_apple_library 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 @@ -435,7 +402,7 @@ jobs: - name: Setup Xcode if: matrix.if run: |- - sudo xcode-select -s /Applications/Xcode_16.2_beta_3.app + sudo xcode-select -s /Applications/Xcode_16.2.app - name: Set tag if: matrix.if run: |- @@ -478,6 +445,10 @@ jobs: --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 }} @@ -486,12 +457,19 @@ jobs: ASC_KEY: ${{ secrets.ASC_KEY }} ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }} ASC_KEY_ISSUER_ID: ${{ secrets.ASC_KEY_ISSUER_ID }} - - name: Download library + - name: Build library if: matrix.if - uses: actions/download-artifact@v4 - with: - name: library-apple - path: clients/apple/Libbox.xcframework + 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: Build if: matrix.if run: |- @@ -503,13 +481,9 @@ jobs: -destination "${{ matrix.destination }}" \ -archivePath "${{ matrix.archive }}" \ -allowProvisioningUpdates \ - -authenticationKeyPath $RUNNER_TEMP/Key.p12 \ + -authenticationKeyPath $ASC_KEY_PATH \ -authenticationKeyID $ASC_KEY_ID \ -authenticationKeyIssuerID $ASC_KEY_ISSUER_ID - env: - MACOS_PROJECT_VERSION: ${{ inputs.macos_project_version }} - ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }} - ASC_KEY_ISSUER_ID: ${{ secrets.ASC_KEY_ISSUER_ID }} - name: Upload to App Store Connect if: matrix.if && matrix.name != 'macOS-standalone' && github.event_name == 'workflow_dispatch' run: |- @@ -518,12 +492,9 @@ jobs: -archivePath "${{ matrix.archive }}" \ -exportOptionsPlist ${{ matrix.upload }} \ -allowProvisioningUpdates \ - -authenticationKeyPath $RUNNER_TEMP/Key.p12 \ + -authenticationKeyPath $ASC_KEY_PATH \ -authenticationKeyID $ASC_KEY_ID \ -authenticationKeyIssuerID $ASC_KEY_ISSUER_ID - env: - ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }} - ASC_KEY_ISSUER_ID: ${{ secrets.ASC_KEY_ISSUER_ID }} - name: Build image if: matrix.if && matrix.name == 'macOS-standalone' && github.event_name == 'workflow_dispatch' run: |- diff --git a/Makefile b/Makefile index 2bc14989..50db1082 100644 --- a/Makefile +++ b/Makefile @@ -182,10 +182,16 @@ release_tvos: build_tvos upload_tvos_app_store update_apple_version: go run ./cmd/internal/update_apple_version +update_macos_version: + MACOS_PROJECT_VERSION=$(shell go run -v ./cmd/internal/app_store_connect next_macos_project_version) go run ./cmd/internal/update_apple_version + release_apple: lib_ios update_apple_version release_ios release_macos release_tvos release_macos_standalone release_apple_beta: update_apple_version release_ios release_macos release_tvos +publish_testflight: + go run -v ./cmd/internal/app_store_connect publish_testflight + test: @go test -v ./... && \ cd test && \ @@ -204,11 +210,11 @@ lib_android: lib_android_debug: go run ./cmd/internal/build_libbox -target android -debug -lib_ios: - go run ./cmd/internal/build_libbox -target ios +lib_apple: + go run ./cmd/internal/build_libbox -target apple -lib_ios_debug: - go run ./cmd/internal/build_libbox -target ios -debug +lib_ios: + go run ./cmd/internal/build_libbox -target apple -platform ios -debug lib: go run ./cmd/internal/build_libbox -target android diff --git a/cmd/internal/app_store_connect/main.go b/cmd/internal/app_store_connect/main.go new file mode 100644 index 00000000..1304b768 --- /dev/null +++ b/cmd/internal/app_store_connect/main.go @@ -0,0 +1,108 @@ +package main + +import ( + "context" + "os" + "strconv" + "time" + + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing/common" + E "github.com/sagernet/sing/common/exceptions" + F "github.com/sagernet/sing/common/format" + + "github.com/cidertool/asc-go/asc" +) + +func main() { + switch os.Args[1] { + case "publish_testflight": + err := publishTestflight(context.Background()) + if err != nil { + log.Fatal(err) + } + case "next_macos_project_version": + err := fetchMacOSVersion(context.Background()) + if err != nil { + log.Fatal(err) + } + default: + log.Fatal("unknown action: ", os.Args[1]) + } +} + +const ( + appID = "6673731168" + groupID = "5c5f3b78-b7a0-40c0-bcad-e6ef87bbefda" +) + +func createClient() *asc.Client { + privateKey, err := os.ReadFile(os.Getenv("ASC_KEY_PATH")) + if err != nil { + log.Fatal(err) + } + tokenConfig, err := asc.NewTokenConfig(os.Getenv("ASC_KEY_ID"), os.Getenv("ASC_KEY_ISSUER_ID"), time.Minute, privateKey) + if err != nil { + log.Fatal(err) + } + return asc.NewClient(tokenConfig.Client()) +} + +func publishTestflight(ctx context.Context) error { + client := createClient() + var buildsToPublish []asc.Build + for _, platform := range []string{ + "IOS", + "MAC_OS", + "TV_OS", + } { + builds, _, err := client.Builds.ListBuilds(ctx, &asc.ListBuildsQuery{ + FilterApp: []string{appID}, + FilterPreReleaseVersionPlatform: []string{platform}, + }) + if err != nil { + return err + } + buildsToPublish = append(buildsToPublish, builds.Data[0]) + } + _, err := client.TestFlight.AddBuildsToBetaGroup(ctx, groupID, common.Map(buildsToPublish, func(it asc.Build) string { + return it.ID + })) + if err != nil { + return err + } + return nil +} + +func fetchMacOSVersion(ctx context.Context) error { + client := createClient() + versions, _, err := client.Apps.ListAppStoreVersionsForApp(ctx, appID, &asc.ListAppStoreVersionsQuery{ + FilterPlatform: []string{"MAC_OS"}, + }) + if err != nil { + return err + } + var versionID string +findVersion: + for _, version := range versions.Data { + switch *version.Attributes.AppStoreState { + case asc.AppStoreVersionStateReadyForSale, + asc.AppStoreVersionStatePendingDeveloperRelease: + versionID = version.ID + break findVersion + } + } + if versionID == "" { + return E.New("no version found") + } + latestBuild, _, err := client.Builds.GetBuildForAppStoreVersion(ctx, versionID, &asc.GetBuildForAppStoreVersionQuery{}) + if err != nil { + return err + } + versionInt, err := strconv.Atoi(*latestBuild.Data.Attributes.Version) + if err != nil { + return E.Cause(err, "parse version code") + } + os.Stdout.WriteString(F.ToString(versionInt+1, "\n")) + return nil +} diff --git a/cmd/internal/build_libbox/main.go b/cmd/internal/build_libbox/main.go index cb493299..e37a9ff4 100644 --- a/cmd/internal/build_libbox/main.go +++ b/cmd/internal/build_libbox/main.go @@ -18,11 +18,13 @@ import ( var ( debugEnabled bool target string + platform string ) func init() { flag.BoolVar(&debugEnabled, "debug", false, "enable debug") flag.StringVar(&target, "target", "android", "target platform") + flag.StringVar(&platform, "platform", "", "specify platform") } func main() { @@ -33,8 +35,8 @@ func main() { switch target { case "android": buildAndroid() - case "ios": - buildiOS() + case "apple": + buildApple() } } @@ -81,7 +83,9 @@ func buildAndroid() { } var bindTarget string - if debugEnabled { + if platform != "" { + bindTarget = platform + } else if debugEnabled { bindTarget = "android/arm64" } else { bindTarget = "android" @@ -129,12 +133,14 @@ func buildAndroid() { } } -func buildiOS() { +func buildApple() { var bindTarget string - if debugEnabled { + if platform != "" { + bindTarget = platform + } else if debugEnabled { bindTarget = "ios" } else { - bindTarget = "ios,iossimulator,tvos,tvossimulator,macos" + bindTarget = "ios,tvos,macos" } args := []string{ diff --git a/go.mod b/go.mod index 42d0b8f3..7683bd5d 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.20 require ( berty.tech/go-libtor v1.0.385 github.com/caddyserver/certmagic v0.20.0 + github.com/cidertool/asc-go v0.5.1 github.com/cloudflare/circl v1.3.7 github.com/cretz/bine v0.2.0 github.com/go-chi/chi/v5 v5.1.0 @@ -60,7 +61,9 @@ require ( require ( github.com/ajg/form v1.5.1 // indirect github.com/andybalholm/brotli v1.0.6 // indirect + github.com/cenkalti/backoff/v4 v4.1.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect @@ -68,6 +71,7 @@ require ( github.com/gobwas/pool v0.2.1 // indirect github.com/google/btree v1.1.3 // indirect github.com/google/go-cmp v0.6.0 // indirect + github.com/google/go-querystring v1.0.0 // indirect github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a // indirect github.com/hashicorp/yamux v0.1.2 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect diff --git a/go.sum b/go.sum index 303654a1..2f96653f 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,10 @@ github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sx github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/caddyserver/certmagic v0.20.0 h1:bTw7LcEZAh9ucYCRXyCpIrSAGplplI0vGYJ4BpCQ/Fc= github.com/caddyserver/certmagic v0.20.0/go.mod h1:N4sXgpICQUskEWpj7zVzvWD41p3NYacrNoZYiRM2jTg= +github.com/cenkalti/backoff/v4 v4.1.0 h1:c8LkOFQTzuO0WBM/ae5HdGQuZPfPxp7lqBRwQRm4fSc= +github.com/cenkalti/backoff/v4 v4.1.0/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cidertool/asc-go v0.5.1 h1:KYki2Y8IXJMOkOXy9y1sdr8tz6IdW2ti770K4bk7WY0= +github.com/cidertool/asc-go v0.5.1/go.mod h1:LyrZWU7DeCh8cWrFwXcpl93ixRUUL2aEZV7/0h07FxA= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -15,6 +19,8 @@ github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbe github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1 h1:CaO/zOnF8VvUfEbhRatPcwKVWamvbYd8tQGRWacE9kU= +github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= @@ -37,6 +43,8 @@ github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a h1:fEBsGL/sjAuJrgah5XqmmYsTLzJp/TO9Lhy39gkverk= github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= @@ -203,6 +211,8 @@ golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 h1:CawjfCvYQH2OU3/TnxLx97WDSUDRABfT18pCOYwc2GE= golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6/go.mod h1:3rxYc4HtVcSG9gVaTs2GEBdehh+sYPOwKtyUWEOTb80= google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY=