name: CI on: push: branches: [main] tags: ['v*'] pull_request: workflow_dispatch: permissions: contents: write packages: read jobs: setup: runs-on: ubuntu-latest outputs: image: ${{ steps.img.outputs.image }} steps: - id: img env: REPO: ${{ github.repository }} run: echo "image=ghcr.io/${REPO,,}/ci:latest" >> "$GITHUB_OUTPUT" lint: needs: setup runs-on: ubuntu-latest container: image: ${{ needs.setup.outputs.image }} credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} steps: - uses: actions/checkout@v6 with: submodules: recursive fetch-depth: 0 - name: Mark workspace safe run: git config --global --add safe.directory "$GITHUB_WORKSPACE" # Rust - name: rustfmt run: | cd zygisk && cargo fmt --check cd ../lsposed/native && cargo fmt --check - name: clippy (zygisk) run: cd zygisk && cargo ndk -t arm64-v8a clippy -- -D warnings - name: clippy (lsposed native) run: cd lsposed/native && cargo ndk -t arm64-v8a clippy -- -D warnings - name: cargo test (zygisk) run: cd zygisk && cargo test # C (kernel module) - name: clang-format run: clang-format --dry-run --Werror kmod/vpnhide_kmod.c # Kotlin - name: ktlint run: ktlint "lsposed/**/*.kt" - name: Android lint run: cd lsposed && ./gradlew --no-daemon :app:lint - name: Kotlin unit tests run: cd lsposed && ./gradlew --no-daemon :app:testDebugUnitTest kmod: runs-on: ubuntu-latest strategy: matrix: kmi: - android12-5.10 - android13-5.10 - android13-5.15 - android14-5.15 - android14-6.1 - android15-6.6 - android16-6.12 container: image: ghcr.io/ylarod/ddk-min:${{ matrix.kmi }}-20260313 env: KMI: ${{ matrix.kmi }} steps: - uses: actions/checkout@v6 with: fetch-depth: 0 - name: Mark workspace safe run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - name: Build and package kernel module run: | cd kmod python3 ./build-zip.py --kmi $KMI - name: Upload artifact uses: actions/upload-artifact@v7 with: name: vpnhide-kmod-${{ matrix.kmi }} path: vpnhide-kmod-${{ matrix.kmi }}.zip if-no-files-found: error zygisk: needs: setup runs-on: ubuntu-latest container: image: ${{ needs.setup.outputs.image }} credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} steps: - uses: actions/checkout@v6 with: submodules: recursive fetch-depth: 0 - name: Mark workspace safe run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - name: Cache cargo uses: actions/cache@v5 with: path: | /usr/local/cargo/registry /usr/local/cargo/git zygisk/target key: cargo-${{ runner.os }}-${{ hashFiles('zygisk/Cargo.lock') }} restore-keys: cargo-${{ runner.os }}- - name: Build module zip env: UPDATE_JSON_URL: https://raw.githubusercontent.com/okhsunrog/vpnhide/main/update-json/update-zygisk.json run: | cd zygisk python3 ./build-zip.py - name: Upload artifact uses: actions/upload-artifact@v7 with: name: vpnhide-zygisk path: zygisk/target/vpnhide-zygisk.zip if-no-files-found: error lsposed: needs: setup runs-on: ubuntu-latest container: image: ${{ needs.setup.outputs.image }} credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} steps: - uses: actions/checkout@v6 with: fetch-depth: 0 - name: Mark workspace safe run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - name: Set up keystore env: KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} run: | KEYSTORE_PATH="$GITHUB_WORKSPACE/lsposed/release.jks" if [ -n "$KEYSTORE_BASE64" ]; then echo "$KEYSTORE_BASE64" | base64 --decode > "$KEYSTORE_PATH" else echo "ANDROID_KEYSTORE_BASE64 is empty (fork PR); generating an ephemeral keystore. Resulting APK is signed with a throwaway key and is NOT suitable for release." KEYSTORE_PASSWORD=ephemeral KEY_ALIAS=ephemeral keytool -genkeypair -v \ -keystore "$KEYSTORE_PATH" \ -storepass "$KEYSTORE_PASSWORD" \ -keypass "$KEYSTORE_PASSWORD" \ -alias "$KEY_ALIAS" \ -keyalg RSA -keysize 4096 -validity 365 \ -dname "CN=vpnhide-fork-ci, O=vpnhide, C=US" fi cat > "$GITHUB_WORKSPACE/lsposed/keystore.properties" < release-notes.md echo "=== release-notes.md ===" cat release-notes.md - name: Create draft release uses: softprops/action-gh-release@v2 with: tag_name: ${{ github.ref_name }} body_path: release-notes.md generate_release_notes: true draft: true files: | dist/*.zip dist/*.apk env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}