# O.M.V. 帝江号 — CircleCI pipeline # # Transcribed from the original .gitlab-ci.yml. The GitLab job did everything in a # single stage; here it is split into a fast, dependency-light gate (`verify-core`, # the with_purego / CGO-disabled build that needs no Android NDK) and the heavy # `build-android` job (gomobile AAR + Gradle APK). The gate must go green before the # expensive Android job starts, so broken patches fail in ~1 minute instead of ~20. # # Orbs do the undifferentiated heavy lifting: # * circleci/android — machine executor with a preinstalled JDK 17 + Android SDK. # * circleci/go — pinned Go toolchain install. # Caching (Go modules/build cache, Gradle) and artifact upload use the native # CircleCI primitives so the keys can be derived from the *generated* works/core/go.sum. version: 2.1 orbs: android: circleci/android@2.5.0 go: circleci/go@1.11.0 parameters: go-version: type: string default: "1.26.2" # We now base directly on upstream SagerNet/sing-box (works/config), whose # .gitmodules points clients/android at SagerNet's own app. The O.M.V. Android # build must instead use *our* fork (branch dev, `other` flavour, our keystore) — # that submodule override was the whole reason omv-dijiang used to build on a # private sing-box mirror. So we re-point it in CI, right after pulling upstream. android-client-url: type: string default: "https://git.sfclub.cc/icybear/sing-box-for-android.git" android-client-branch: type: string default: "dev" commands: # bin/update clones the latest `testing` sing-box (see works/config) and bin/apply-ci # materialises works/core = upstream + works/patch/*. Shared by both jobs. sync-upstream: description: Fetch latest testing sing-box and apply the O.M.V. patches steps: - run: name: bin/update + bin/apply-ci command: | git config --global user.name "${GIT_AUTHOR_NAME:-omv-ci}" git config --global user.email "${GIT_AUTHOR_EMAIL:-omv-ci@local}" bin/update bin/apply-ci restore-go-cache: description: Restore the Go module + build cache keyed on the generated go.sum steps: - restore_cache: keys: - omv-go-v1-{{ arch }}-{{ checksum "works/core/go.sum" }} - omv-go-v1-{{ arch }}- jobs: # --------------------------------------------------------------------------- # Fast gate: prove works/core compiles without CGO/NDK (with_purego). # This is the build the machine can actually run; the Android AAR needs an NDK. # --------------------------------------------------------------------------- verify-core: docker: - image: golang:<< pipeline.parameters.go-version >>-bookworm resource_class: large working_directory: ~/project environment: CGO_ENABLED: "0" GOFLAGS: "-mod=mod" GOMODCACHE: /go/pkg/mod GOCACHE: /root/.cache/go-build # OTHERS build tags minus with_naive_outbound (needs cgo), plus with_purego. BUILD_TAGS: "with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_ocm,with_cloudflared,with_usbip,badlinkname,tfogo_checklinkname0,with_purego" steps: - checkout - run: name: Install system dependencies command: | apt-get update apt-get install -y --no-install-recommends git rsync patch unzip curl ca-certificates - sync-upstream - restore-go-cache - run: name: Build core + libbox (with_purego, no NDK) working_directory: ~/project/works/core command: | go mod tidy version="$(git describe --tags --always)-${CIRCLE_SHA1:0:8}" echo "building $version" # -checklinkname=0 authorises upstream's //go:linkname pulls (LDFLAGS file). go build -v -tags "$BUILD_TAGS" \ -ldflags "-X 'github.com/sagernet/sing-box/constant.Version=$version' -checklinkname=0" \ -o /tmp/sing-box ./cmd/sing-box # The AAR wraps experimental/libbox; compile it too so the mobile-facing # code is covered even though we don't cross-compile with gomobile here. go build -v -tags "$BUILD_TAGS" ./experimental/libbox - run: name: Validate O.M.V. sample configs command: | for c in minecraft/server minecraft/client obfhttp/server obfhttp/client; do echo "check config/$c/config.json" /tmp/sing-box check -c "config/$c/config.json" done - save_cache: key: omv-go-v1-{{ arch }}-{{ checksum "works/core/go.sum" }} paths: - /go/pkg/mod - /root/.cache/go-build - store_artifacts: path: /tmp/sing-box destination: sing-box-linux-amd64 # --------------------------------------------------------------------------- # Full Android build: gomobile AAR (CGO + NDK) then Gradle assembleOtherRelease. # Mirrors the original GitLab job. # --------------------------------------------------------------------------- build-android: executor: name: android/android-machine resource-class: large # `android:default` is CircleCI's rolling Linux+Android machine image (JDK 17, # Android SDK preinstalled). Pin to a dated tag (e.g. 2024.11.1) for reproducibility. tag: default environment: ANDROID_NDK_VERSION: r28 GOFLAGS: "-mod=mod" GOMODCACHE: /home/circleci/go/pkg/mod GOCACHE: /home/circleci/.cache/go-build # Placeholder debug-keystore password carried over from the GitLab CI. For real # releases DO NOT commit this — set LOCAL_PROPERTIES in a CircleCI context or # project environment variable (base64 of KEYSTORE_PASS/ALIAS_NAME/ALIAS_PASS). LOCAL_PROPERTIES: "S0VZU1RPUkVfUEFTUz0xMTQ1MTQKQUxJQVNfTkFNRT1hbGlhcwpBTElBU19QQVNTPTExNDUxNAo=" steps: - checkout - go/install: version: << pipeline.parameters.go-version >> - run: name: Install extra system dependencies command: sudo apt-get update && sudo apt-get install -y --no-install-recommends rsync patch unzip - run: name: Provision Android SDK + NDK command: bash ./setup-ndk.sh - sync-upstream - run: name: Re-point clients/android at our fork, then init it working_directory: ~/project/works/core command: | # Upstream's gitlink pins a SagerNet android commit our fork doesn't have, # so swap the URL, pin the branch, and use --remote to check out our fork's # branch tip instead of the (unreachable) pinned SHA. git submodule set-url clients/android "<< pipeline.parameters.android-client-url >>" git config -f .gitmodules submodule.clients/android.branch "<< pipeline.parameters.android-client-branch >>" git submodule sync clients/android git submodule update --init --remote --recursive clients/android echo "clients/android now:" && git -C clients/android remote get-url origin && git -C clients/android log --oneline -1 - restore-go-cache - restore_cache: keys: - omv-gradle-v1-{{ checksum "works/core/clients/android/gradle/libs.versions.toml" }} - omv-gradle-v1- - run: name: Build libbox AAR (gomobile) working_directory: ~/project/works/core command: | export ANDROID_HOME="$CIRCLE_WORKING_DIRECTORY/Android/Sdk" export ANDROID_SDK_ROOT="$ANDROID_HOME" version="$(git describe --tags --always)-${CIRCLE_SHA1:0:8}" echo "building version $version" make lib_install export PATH="$PATH:$(go env GOPATH)/bin" go mod tidy make lib_android - run: name: Assemble APK (assembleOtherRelease) working_directory: ~/project/works/core command: | export ANDROID_HOME="$CIRCLE_WORKING_DIRECTORY/Android/Sdk" # clients/android is already checked out at our fork's branch tip (see the # "Re-point clients/android" step, which uses `submodule update --remote`). go run -v ./cmd/internal/update_android_version --ci --nightly mkdir -p clients/android/app/libs cp ./*.aar clients/android/app/libs cd clients/android ./gradlew --no-daemon :app:assembleOtherRelease - run: name: Collect artifacts working_directory: ~/project/works/core command: | mkdir -p /tmp/dist cp clients/android/app/build/outputs/apk/other/release/*arm64-v8a.apk /tmp/dist/ VERSION_CODE=$(grep VERSION_CODE clients/android/version.properties | cut -d= -f2) VERSION_NAME=$(grep VERSION_NAME clients/android/version.properties | cut -d= -f2) echo "Built versionCode=$VERSION_CODE versionName=$VERSION_NAME" - save_cache: key: omv-go-v1-{{ arch }}-{{ checksum "works/core/go.sum" }} paths: - /home/circleci/go/pkg/mod - /home/circleci/.cache/go-build - save_cache: key: omv-gradle-v1-{{ checksum "works/core/clients/android/gradle/libs.versions.toml" }} paths: - /home/circleci/.gradle/caches - /home/circleci/.gradle/wrapper - store_artifacts: path: /tmp/dist destination: dist workflows: build: jobs: - verify-core - build-android: requires: - verify-core