Build and Release OnePlus Kernels #489
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build and Release OnePlus Kernels | |
| permissions: | |
| contents: write | |
| actions: write | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| make_release: | |
| description: 'Do you want to create a release?' | |
| required: true | |
| type: boolean | |
| default: false | |
| op_model: | |
| description: 'Select the OnePlus kernels to build' | |
| required: true | |
| type: choice | |
| options: | |
| - OOS14+15+16 | |
| - OOS15+16 | |
| - OOS14+15 | |
| - OOS16 | |
| - OOS15 | |
| - OOS14 | |
| - android16-6.12 | |
| - android15-6.6 | |
| - android14-6.1 | |
| - android13-5.15 | |
| - android12-5.10 | |
| default: OOS14+15+16 | |
| ksu_options: | |
| description: 'Enter KernelSU build json' | |
| required: true | |
| type: string | |
| default: '[{"type":"ksun","hash":"dev"}]' | |
| optimize_level: | |
| description: "Compiler optimization level" | |
| required: true | |
| type: choice | |
| options: [O2, O3] | |
| default: O2 | |
| clean_build: | |
| description: 'Clean build (no ccache)' | |
| type: boolean | |
| default: false | |
| android12-5_10_susfs_branch_or_commit: | |
| description: 'Enter SusFS Branch or commit hash for android12-5.10' | |
| type: string | |
| default: '' | |
| android13-5_15_susfs_branch_or_commit: | |
| description: 'Enter SusFS Branch or commit hash for android13-5.15' | |
| type: string | |
| default: '' | |
| android14-6_1_susfs_branch_or_commit: | |
| description: 'Enter SusFS Branch or commit hash for android14-6.1' | |
| type: string | |
| default: '' | |
| android15-6_6_susfs_branch_or_commit: | |
| description: 'Enter SusFS Branch or commit hash for android15-6.6' | |
| type: string | |
| default: '' | |
| android16-6_12_susfs_branch_or_commit: | |
| description: 'Enter SusFS Branch or commit hash for android16-6.12' | |
| type: string | |
| default: '' | |
| jobs: | |
| set-op-model: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| matrix: ${{ steps.set-matrix.outputs.matrix }} | |
| device_count: ${{ steps.set-matrix.outputs.count }} | |
| active_gki_keys: ${{ steps.set-matrix.outputs.active_gki_keys }} | |
| susfs_hash_android12_5_10: ${{ steps.set-matrix.outputs.susfs_hash_android12_5_10 }} | |
| susfs_hash_android13_5_15: ${{ steps.set-matrix.outputs.susfs_hash_android13_5_15 }} | |
| susfs_hash_android14_6_1: ${{ steps.set-matrix.outputs.susfs_hash_android14_6_1 }} | |
| susfs_hash_android15_6_6: ${{ steps.set-matrix.outputs.susfs_hash_android15_6_6 }} | |
| susfs_hash_android16_6_12: ${{ steps.set-matrix.outputs.susfs_hash_android16_6_12 }} | |
| ksu_resolved_hash: ${{ steps.set-matrix.outputs.ksu_resolved_hash }} | |
| ksu_options_normalized: ${{ steps.set-matrix.outputs.ksu_options_normalized }} | |
| susfs_base_version: ${{ steps.set-matrix.outputs.susfs_base_version }} | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| GH_HTTP_TIMEOUT: 600 | |
| steps: | |
| - name: 📥 Checkout Code (to access configs/) | |
| uses: actions/checkout@v6 | |
| with: | |
| sparse-checkout: | | |
| configs/ | |
| sparse-checkout-cone-mode: false | |
| - name: 🔍 Generate build matrix | |
| id: set-matrix | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| echo "::group::Matrix generation" | |
| input="${{ github.event.inputs.op_model }}" | |
| ksu_options_raw='${{ github.event.inputs.ksu_options }}' | |
| if ! ksu_options_normalized=$(echo "$ksu_options_raw" | jq -c 'map(if .type then .type |= ascii_upcase | if .hash == null then if .type == "KSUN" then .hash = "dev" elif .type == "KSU" then .hash = "main" else .hash end else . end else error("No type found") end)' 2>&1); then | |
| echo "::error::ksu_options validation failed: $ksu_options_normalized" | |
| exit 1 | |
| fi | |
| echo "ksu_options_normalized=$ksu_options_normalized" >> $GITHUB_OUTPUT | |
| echo "[" > matrix.json | |
| mapfile -t all_json_files < <(find configs/ -name "*.json" -print0 | xargs -0 -n1) | |
| for i in "${!all_json_files[@]}"; do | |
| file="${all_json_files[$i]}" | |
| if [ -f "$file" ]; then | |
| jq -r '.' "$file" >> matrix.json | |
| if [ $((i+1)) -lt ${#all_json_files[@]} ]; then | |
| echo "," >> matrix.json | |
| fi | |
| fi | |
| done | |
| echo "]" >> matrix.json | |
| jq_filter="." | |
| case "$input" in | |
| OOS14+15+16) | |
| ;; | |
| OOS15+16) | |
| jq_filter="map(select(.os_version == \"OOS15\" or .os_version == \"OOS16\"))" | |
| ;; | |
| OOS14+15) | |
| jq_filter="map(select(.os_version == \"OOS14\" or .os_version == \"OOS15\"))" | |
| ;; | |
| OOS16) | |
| jq_filter="map(select(.os_version == \"OOS16\"))" | |
| ;; | |
| OOS15) | |
| jq_filter="map(select(.os_version == \"OOS15\"))" | |
| ;; | |
| OOS14) | |
| jq_filter="map(select(.os_version == \"OOS14\"))" | |
| ;; | |
| android*-*.*) | |
| # Extract android version and kernel version | |
| IFS='-' read -r av kv <<< "$input" | |
| # Build android*-* only for OOS15 and OOS16 | |
| jq_filter="map(select(.os_version == \"OOS15\" or .os_version == \"OOS16\")) | map(select(.android_version == \"$av\" and .kernel_version == \"$kv\"))" | |
| echo "ℹ️ Android-Kernel filter applied: $av-$kv" | |
| echo " Restricted to: OOS15 and OOS16 only" | |
| ;; | |
| *) | |
| echo "::warning::Unknown input '$input'. Using empty filter." | |
| jq_filter="map(select(false))" | |
| ;; | |
| esac | |
| filtered=$(jq -c "$jq_filter" matrix.json) | |
| count=$(jq 'length' <<<"$filtered") | |
| if [ "$count" -eq 0 ]; then | |
| echo "::error::No config files found for input '$input' after applying filters!" | |
| echo "" | |
| echo "Available configurations:" | |
| jq -r '.[] | " - \(.model) (\(.os_version), \(.android_version)-\(.kernel_version))"' matrix.json | |
| exit 1 | |
| fi | |
| echo "$filtered" | jq '.' > matrix.json | |
| # For each device + each ksu option → one combined entry | |
| merged_matrix=$(jq -n --argjson devices "$filtered" --argjson ksu_list "$ksu_options_normalized" '[ $devices[] as $dev | $ksu_list[] as $ksu | ($dev + {ksu_type: $ksu.type, ksu_hash: $ksu.hash}) ]') | |
| final_count=$(echo "$merged_matrix" | jq 'length') | |
| echo "✅ Found $final_count device(s) to build" | |
| echo "" | |
| echo "Selected devices:" | |
| jq -r '.[] | " - \(.model) (\(.os_version), \(.android_version)-\(.kernel_version), \(.ksu_type) - \(.ksu_hash))"' <<<"$merged_matrix" | |
| echo "count=$count" >> "$GITHUB_OUTPUT" | |
| ksu_type=$(echo "$ksu_options_normalized" | jq -r '.[0].type') | |
| ksu_ref=$(echo "$ksu_options_normalized" | jq -r '.[0].hash') | |
| if [ "$ksu_type" == "KSUN" ]; then | |
| KSU_REPO_OWNER="KernelSU-Next" | |
| KSU_REPO_NAME="KernelSU-Next" | |
| else | |
| KSU_REPO_OWNER="tiann" | |
| KSU_REPO_NAME="KernelSU" | |
| fi | |
| HEAD_REF="refs/heads/${ksu_ref}" | |
| TAG_REF="refs/tags/${ksu_ref}" | |
| QUERY='query($owner: String!, $name: String!, $headRef: String!, $tagRef: String!, $objRef: String!) { | |
| repository(owner: $owner, name: $name) { | |
| hb: ref(qualifiedName: $headRef) { t: target { ... on Commit { o: oid } } } | |
| ht: ref(qualifiedName: $tagRef) { t: target { ... on Commit { o: oid } } } | |
| ho: object(expression: $objRef) { ... on Commit { o: oid } } | |
| } | |
| }' | |
| MAX_RETRIES=3 | |
| RETRY_COUNT=0 | |
| RETRY_DELAY=5 # Seconds to wait between retries | |
| echo "Resolving $ksu_type hash ($ksu_ref)..." | |
| until [ $RETRY_COUNT -ge $MAX_RETRIES ]; do | |
| RESULT=$(gh api graphql -f query="$QUERY" -f owner="$KSU_REPO_OWNER" -f name="$KSU_REPO_NAME" -f headRef="$HEAD_REF" -f tagRef="$TAG_REF" -f objRef="$ksu_ref" 2>/dev/null) | |
| EXIT_CODE=$? | |
| if [ $EXIT_CODE -eq 0 ] && [ ! -z "$RESULT" ]; then | |
| echo " ✅ API Success" | |
| break | |
| fi | |
| RETRY_COUNT=$((RETRY_COUNT + 1)) | |
| echo "::warning::API failed (Attempt $RETRY_COUNT/$MAX_RETRIES). Retrying in ${RETRY_DELAY}s..." | |
| sleep $RETRY_DELAY | |
| done | |
| if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then | |
| echo "::error::GitHub API unreachable. Cannot validate $ksu_ref" | |
| exit 1 | |
| fi | |
| resolved_sha=$(echo "$RESULT" | jq -r '.data.repository | (.hb.t.o // .ht.t.o // .ho.o // "unknown")') | |
| if [ "$resolved_sha" == "unknown" ]; then | |
| echo "::error::Ref/Hash '$ksu_ref' does not exist in $KSU_REPO_OWNER/$KSU_REPO_NAME" | |
| exit 1 | |
| fi | |
| echo " ✅ Resolved: $ksu_type/$ksu_ref → $resolved_sha" | |
| echo "ksu_resolved_hash=$resolved_sha" >> "$GITHUB_OUTPUT" | |
| # Inject ksu_resolved_hash into each device in the matrix | |
| merged_matrix=$(echo "$merged_matrix" | jq --arg resolved_sha "$resolved_sha" 'map(.ksu_resolved_hash = $resolved_sha)') | |
| # SUSFS hash fetch | |
| SUSFS_REPO="https://gitlab.com/simonpunk/susfs4ksu.git" | |
| PROJECT_ID="simonpunk%2fsusfs4ksu" | |
| declare -A default_branches=( | |
| ["android12-5.10"]="gki-android12-5.10" | |
| ["android13-5.15"]="gki-android13-5.15" | |
| ["android14-6.1"]="gki-android14-6.1" | |
| ["android15-6.6"]="gki-android15-6.6" | |
| ["android16-6.12"]="gki-android16-6.12" | |
| ) | |
| declare -A user_inputs=( | |
| ["android12-5.10"]="${{ inputs.android12-5_10_susfs_branch_or_commit }}" | |
| ["android13-5.15"]="${{ inputs.android13-5_15_susfs_branch_or_commit }}" | |
| ["android14-6.1"]="${{ inputs.android14-6_1_susfs_branch_or_commit }}" | |
| ["android15-6.6"]="${{ inputs.android15-6_6_susfs_branch_or_commit }}" | |
| ["android16-6.12"]="${{ inputs.android16-6_12_susfs_branch_or_commit }}" | |
| ) | |
| mapfile -t active_keys < <( | |
| echo "$merged_matrix" \ | |
| | jq -r '.[] | select(.susfs == true) | "\(.android_version)-\(.kernel_version)"' \ | |
| | sort -u | |
| ) | |
| echo "🔍 Resolving SUSFS hashes for: ${active_keys[*]:-none}" | |
| declare -A susfs_hashes | |
| for key in "${active_keys[@]}"; do | |
| default_val="${default_branches[$key]}" | |
| user_val="${user_inputs[$key]:-$default_val}" | |
| MAX_RETRIES=3 | |
| RETRY_COUNT=0 | |
| RETRY_DELAY=5 | |
| resolved="" | |
| until [ $RETRY_COUNT -ge $MAX_RETRIES ]; do | |
| # We query the commit endpoint which accepts Branch, Tag, or SHA | |
| RESULT=$(curl -s --fail "https://gitlab.com/api/v4/projects/${PROJECT_ID}/repository/commits/${user_val}") | |
| EXIT_CODE=$? | |
| if [ $EXIT_CODE -eq 0 ] && [ -n "$RESULT" ]; then | |
| resolved=$(echo "$RESULT" | jq -r '.id') | |
| echo " ✅ Query for $key input field Success" | |
| break | |
| fi | |
| RETRY_COUNT=$((RETRY_COUNT + 1)) | |
| echo "::warning::GitLab API failed (Attempt $RETRY_COUNT/$MAX_RETRIES). Retrying..." | |
| sleep $RETRY_DELAY | |
| done | |
| # Final Validation | |
| if [ -z "$resolved" ] || [ "$resolved" = "null" ]; then | |
| echo "::error::Could not resolve SUSFS ref '$user_val' for $key on GitLab." | |
| exit 1 | |
| fi | |
| susfs_hashes["$key"]="$resolved" | |
| echo " ✅ Resolved: $key → $resolved" | |
| done | |
| # Write CSV list of active GKI versions | |
| active_gki_keys_csv=$(IFS=','; echo "${active_keys[*]:-}") | |
| echo "active_gki_keys=$active_gki_keys_csv" >> "$GITHUB_OUTPUT" | |
| # Write hash to GITHUB_OUTPUT | |
| echo "susfs_hash_android12_5_10=${susfs_hashes[android12-5.10]:-unknown}" >> "$GITHUB_OUTPUT" | |
| echo "susfs_hash_android13_5_15=${susfs_hashes[android13-5.15]:-unknown}" >> "$GITHUB_OUTPUT" | |
| echo "susfs_hash_android14_6_1=${susfs_hashes[android14-6.1]:-unknown}" >> "$GITHUB_OUTPUT" | |
| echo "susfs_hash_android15_6_6=${susfs_hashes[android15-6.6]:-unknown}" >> "$GITHUB_OUTPUT" | |
| echo "susfs_hash_android16_6_12=${susfs_hashes[android16-6.12]:-unknown}" >> "$GITHUB_OUTPUT" | |
| # Fetch SUSFS_VERSION | |
| susfs_base_version="unknown" | |
| if [ ${#active_keys[@]} -gt 0 ]; then | |
| first_key="${active_keys[0]}" | |
| first_user_val="${user_inputs[$first_key]:-}" | |
| first_ref="${first_user_val:-${default_branches[$first_key]:-gki-android15-6.6}}" | |
| echo "🔍 Fetching SUSFS_VERSION from susfs.h (ref: $first_ref)..." | |
| MAX_RETRIES=3 | |
| RETRY_COUNT=0 | |
| RETRY_DELAY=5 | |
| until [ $RETRY_COUNT -ge $MAX_RETRIES ]; do | |
| RAW_CONTENT=$(curl -s --fail \ | |
| "https://gitlab.com/api/v4/projects/${PROJECT_ID}/repository/files/kernel_patches%2Finclude%2Flinux%2Fsusfs.h/raw?ref=${first_ref}") | |
| EXIT_CODE=$? | |
| if [ $EXIT_CODE -eq 0 ] && [ -n "$RAW_CONTENT" ]; then | |
| extracted=$(echo "$RAW_CONTENT" | grep '#define SUSFS_VERSION' | awk -F'"' '{print $2}') | |
| if [ -n "$extracted" ]; then | |
| susfs_base_version="$extracted" | |
| echo " ✅ SUSFS_VERSION = $susfs_base_version" | |
| break | |
| fi | |
| fi | |
| RETRY_COUNT=$((RETRY_COUNT + 1)) | |
| echo "::warning::Failed to fetch susfs.h (Attempt $RETRY_COUNT/$MAX_RETRIES). Retrying in ${RETRY_DELAY}s..." | |
| sleep $RETRY_DELAY | |
| done | |
| if [ "$susfs_base_version" = "unknown" ]; then | |
| echo "::warning::Could not extract SUSFS_VERSION from susfs.h. SUSFS_BASE_VERSION will be 'unknown'." | |
| fi | |
| # Warn if other GKI keys use different manual refs than the first one (possible version inconsistency) | |
| if [ ${#active_keys[@]} -gt 1 ]; then | |
| for key in "${active_keys[@]:1}"; do | |
| other_val="${user_inputs[$key]:-}" | |
| if [ -n "$other_val" ] && [ "$other_val" != "$first_ref" ]; then | |
| echo "::warning::GKI key '$key' uses ref '$other_val', different from '$first_ref' used to extract SUSFS_VERSION. Verify that the versions in susfs.h match." | |
| fi | |
| done | |
| fi | |
| else | |
| echo "ℹ️ No active SUSFS keys — skipping SUSFS_VERSION fetch." | |
| fi | |
| echo "susfs_base_version=$susfs_base_version" >> "$GITHUB_OUTPUT" | |
| # Inject susfs_resolved_hash into each device in the matrix | |
| susfs_hashes_json=$(jq -n \ | |
| --arg a12 "${susfs_hashes[android12-5.10]:-unknown}" \ | |
| --arg a13 "${susfs_hashes[android13-5.15]:-unknown}" \ | |
| --arg a14 "${susfs_hashes[android14-6.1]:-unknown}" \ | |
| --arg a15 "${susfs_hashes[android15-6.6]:-unknown}" \ | |
| --arg a16 "${susfs_hashes[android16-6.12]:-unknown}" \ | |
| '{ | |
| "android12-5.10": $a12, | |
| "android13-5.15": $a13, | |
| "android14-6.1": $a14, | |
| "android15-6.6": $a15, | |
| "android16-6.12": $a16 | |
| }') | |
| merged_matrix=$(echo "$merged_matrix" | jq \ | |
| --argjson hashes "$susfs_hashes_json" \ | |
| '[.[] | . + {susfs_resolved_hash: ($hashes["\(.android_version)-\(.kernel_version)"] // "unknown")}]') | |
| # Recalculate wrapped with updated matrix and write output | |
| wrapped=$(jq -n --argjson items "$merged_matrix" '{ include: $items }') | |
| echo "matrix=$(jq -c . <<< "$wrapped")" >> "$GITHUB_OUTPUT" | |
| echo "::endgroup::" | |
| - name: Upload build matrix | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: build-matrix | |
| path: matrix.json | |
| archive: false | |
| retention-days: 7 | |
| - name: 📊 Build plan summary | |
| run: | | |
| ksu_type="${{ fromJSON(steps.set-matrix.outputs.ksu_options_normalized)[0].type }}" | |
| ksu_ref="${{ fromJSON(steps.set-matrix.outputs.ksu_options_normalized)[0].hash }}" | |
| ksu_display="" | |
| if [ "$ksu_type" = "KSUN" ] || [ "$ksu_type" = "KSU" ]; then | |
| if [[ "$ksu_ref" =~ ^[0-9a-f]{40}$ ]]; then | |
| ksu_display+="📌 \`$ksu_type\`, \`$ksu_ref\`" | |
| else | |
| ksu_display+="🔀 \`$ksu_type\`, \`$ksu_ref\` (\`${{ steps.set-matrix.outputs.ksu_resolved_hash }}\`)" | |
| fi | |
| fi | |
| { | |
| cat << 'EOF' | |
| ## 🎯 Build Plan | |
| **Target:** ${{ inputs.op_model }} | |
| **Devices:** ${{ steps.set-matrix.outputs.count }} | |
| **Configuration:** | |
| EOF | |
| echo "- KSU Config: $ksu_display" | |
| cat << 'EOF' | |
| - Optimization: ${{ inputs.optimize_level }} | |
| - Clean Build/No Ccache: ${{ inputs.clean_build && '✅ Yes' || '❌ No' }} | |
| - Create Release: ${{ inputs.make_release && '✅ Yes' || '❌ No' }} | |
| **SUSFS Configuration:** | |
| EOF | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| echo "- **Version:** 📦 \`${{ steps.set-matrix.outputs.susfs_base_version }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| # Display SUSFS config for each kernel version | |
| declare -A susfs_inputs=( | |
| ["android12-5.10"]="${{ inputs.android12-5_10_susfs_branch_or_commit }}" | |
| ["android13-5.15"]="${{ inputs.android13-5_15_susfs_branch_or_commit }}" | |
| ["android14-6.1"]="${{ inputs.android14-6_1_susfs_branch_or_commit }}" | |
| ["android15-6.6"]="${{ inputs.android15-6_6_susfs_branch_or_commit }}" | |
| ["android16-6.12"]="${{ inputs.android16-6_12_susfs_branch_or_commit }}" | |
| ) | |
| declare -A step_hashes=( | |
| ["android12-5.10"]="${{ steps.set-matrix.outputs.susfs_hash_android12_5_10 }}" | |
| ["android13-5.15"]="${{ steps.set-matrix.outputs.susfs_hash_android13_5_15 }}" | |
| ["android14-6.1"]="${{ steps.set-matrix.outputs.susfs_hash_android14_6_1 }}" | |
| ["android15-6.6"]="${{ steps.set-matrix.outputs.susfs_hash_android15_6_6 }}" | |
| ["android16-6.12"]="${{ steps.set-matrix.outputs.susfs_hash_android16_6_12 }}" | |
| ) | |
| # Iterate only on the GKI versions present in this run | |
| IFS=',' read -ra active_keys_display \ | |
| <<< "${{ steps.set-matrix.outputs.active_gki_keys }}" | |
| for key in "${active_keys_display[@]}"; do | |
| value="${susfs_inputs[$key]:-}" | |
| fetched_hash="${step_hashes[$key]:-unknown}" | |
| if [ -z "$value" ]; then | |
| # Auto: no input > hash resolved by ls-remote | |
| echo "- $key: 🔄 auto (\`$fetched_hash\`)" >> $GITHUB_STEP_SUMMARY | |
| elif [[ "$value" =~ ^[0-9a-f]{40}$ ]]; then | |
| # Manual 40-char hash > direct passthrough | |
| echo "- $key: 📌 \`$value\`" >> $GITHUB_STEP_SUMMARY | |
| else | |
| # Branch name > show branch + resolved hash | |
| echo "- $key: 🔀 \`$value\` (\`$fetched_hash\`)" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| done | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "> **💡 Note:** Hashes are resolved at run time via API calls before builds start." >> $GITHUB_STEP_SUMMARY | |
| # Add OOS restriction note for android-kernel filters | |
| if [[ "${{ inputs.op_model }}" == android*-*.* ]]; then | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "> **⚠️ Android-Kernel Filter:** Only OOS15 and OOS16 devices will be built for \`${{ inputs.op_model }}\`" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| build: | |
| name: build (${{ matrix.model }}, ${{ matrix.soc }}, ${{ matrix.branch }}, ${{ matrix.manifest }}, ${{ matrix.android_version }}, ${{ matrix.kernel_version }}, ${{ matrix.os_version }}, ${{ matrix.ksu_type }}) | |
| needs: set-op-model | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: ${{ fromJSON(needs.set-op-model.outputs.matrix) }} | |
| outputs: | |
| ksun_ver: ${{ steps.build-stat.outputs.ksu_version }} | |
| ksu_ver: ${{ steps.build-stat.outputs.ksu_version }} | |
| steps: | |
| - name: 🧹 Emergency Disk Cleanup | |
| if: ${{ matrix.disk_cleanup }} | |
| run: | | |
| echo "::group::Disk Usage Before Cleanup" | |
| df -h | |
| echo "::endgroup::" | |
| echo "::group::Removing Unnecessary Software" | |
| sudo rm -rf /usr/share/dotnet | |
| sudo rm -rf /usr/local/lib/android | |
| sudo rm -rf /opt/ghc | |
| sudo rm -rf /opt/hostedtoolcache/CodeQL | |
| sudo apt-get clean | |
| if command -v docker >/dev/null 2>&1; then | |
| docker rmi $(docker images -q) 2>/dev/null || true | |
| fi | |
| echo "::endgroup::" | |
| echo "::group::Disk Usage After Cleanup" | |
| df -h | |
| AVAIL=$(df -h / | awk 'NR==2 {print $4}') | |
| echo "✅ Available space: $AVAIL" | |
| echo "::endgroup::" | |
| - name: Download Apache Arrow's util_free_space.sh | |
| if: ${{ matrix.disk_cleanup }} | |
| run: | | |
| curl -L -o util_free_space.sh https://raw.githubusercontent.com/apache/arrow/main/ci/scripts/util_free_space.sh | |
| chmod +x util_free_space.sh | |
| ./util_free_space.sh | |
| - name: 📥 Checkout Code | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 1 | |
| - name: Install Minimal Dependencies | |
| run: | | |
| set -euo pipefail | |
| echo "::group::Install dependencies" | |
| sudo apt-get -o Acquire::Retries=3 update -qq | |
| sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ | |
| git curl ca-certificates build-essential clang lld flex bison \ | |
| libelf-dev libssl-dev libncurses-dev zlib1g-dev liblz4-tool \ | |
| libxml2-utils rsync unzip dwarves file python3 ccache jq bc dos2unix kmod libdw-dev elfutils | |
| sudo apt-get clean | |
| echo "✅ Dependencies installed" | |
| echo "::endgroup::" | |
| - name: 📦 Disk usage (pre-build) | |
| run: | | |
| echo "::group::Disk usage pre-build" | |
| df -h / | |
| du -sh "$GITHUB_WORKSPACE" 2>/dev/null || true | |
| sudo rm -rf /tmp/* || true | |
| echo "::endgroup::" | |
| - name: ♻️ Configure ccache (bounded) | |
| if: ${{ inputs.clean_build != true }} | |
| run: | | |
| if command -v ccache >/dev/null 2>&1; then | |
| echo "::group::ccache configuration" | |
| ccache -o max_size=1.0G | |
| ccache -o compression=true | |
| ccache -o compression_level=3 | |
| ccache -s | |
| echo "::endgroup::" | |
| fi | |
| - name: 🧹 Prepare op_config_json (without KSU fields) | |
| id: prepare_config | |
| shell: bash | |
| run: | | |
| echo "config_json=$(jq -nc --argjson m '${{ toJSON(matrix) }}' '$m | del(.ksu_type, .ksu_hash, .ksu_resolved_hash)')" >> "$GITHUB_OUTPUT" | |
| - name: 🔨 Build Kernel | |
| id: build | |
| uses: ./.github/actions | |
| with: | |
| op_config_json: ${{ steps.prepare_config.outputs.config_json }} | |
| ksu_type: ${{ matrix.ksu_type }} | |
| ksu_branch_or_hash: ${{ matrix.ksu_resolved_hash }} | |
| susfs_commit_hash_or_branch: ${{ matrix.susfs_resolved_hash }} | |
| optimize_level: ${{ inputs.optimize_level }} | |
| clean: ${{ inputs.clean_build }} | |
| - name: 📊 Build statistics | |
| id: build-stat | |
| if: always() | |
| run: | | |
| echo "::group::Build Statistics" | |
| echo "Device: ${{ matrix.model }}" | |
| echo "OS Version: ${{ matrix.os_version }}" | |
| echo "Kernel: ${{ matrix.android_version }}-${{ matrix.kernel_version }}" | |
| if [ "${{ matrix.susfs }}" = true ]; then | |
| echo "SUSFS Hash: ${{ matrix.susfs_resolved_hash }}" | |
| fi | |
| echo "Status: ${{ job.status }}" | |
| if [ "${{ steps.build.outcome }}" = "success" ]; then | |
| echo "" | |
| echo "✅ Build completed successfully" | |
| echo "" | |
| echo "Outputs:" | |
| echo " - Kernel: ${{ steps.build.outputs.kernel_version }}" | |
| if [ "${{ matrix.ksu_type }}" = "KSUN" ]; then | |
| echo " - KSU Next: v${{ steps.build.outputs.ksu_version }}" | |
| echo "ksun_ver=${{ steps.build.outputs.ksu_version }}" >> "$GITHUB_OUTPUT" | |
| echo "ksu_ver=" >> "$GITHUB_OUTPUT" | |
| else | |
| echo " - KSU: v${{ steps.build.outputs.ksu_version }}" | |
| echo "ksun_ver=" >> "$GITHUB_OUTPUT" | |
| echo "ksu_ver=${{ steps.build.outputs.ksu_version }}" >> "$GITHUB_OUTPUT" | |
| fi | |
| if [ "${{ matrix.susfs }}" = true ]; then | |
| echo " - SUSFS: ${{ steps.build.outputs.susfs_version }}" | |
| fi | |
| echo " - Build time: ${{ steps.build.outputs.build_time }}s" | |
| if [ "${{ inputs.clean_build }}" != "true" ]; then | |
| echo " - ccache hit rate: ${{ steps.build.outputs.ccache_hit_rate }}" | |
| echo " - ccache direct rate: ${{ steps.build.outputs.ccache_direct_rate }}" | |
| else | |
| echo " - ccache: disabled (clean build)" | |
| fi | |
| if [ -n "${{ steps.build.outputs.warnings }}" ]; then | |
| echo " - Warnings: ${{ steps.build.outputs.warnings }}" | |
| fi | |
| else | |
| echo "❌ Build failed" | |
| fi | |
| echo "::endgroup::" | |
| - name: 📝 Job summary | |
| if: always() | |
| run: | | |
| cat >> $GITHUB_STEP_SUMMARY << EOF | |
| ### ${{ matrix.model }} (${{ matrix.os_version }}) - ${{ job.status == 'success' && '✅ Success' || '❌ Failed' }} | |
| **Kernel:** ${{ matrix.android_version }}-${{ matrix.kernel_version }} | |
| EOF | |
| if [ "${{ matrix.susfs }}" = true ]; then | |
| cat >> $GITHUB_STEP_SUMMARY << EOF | |
| **SUSFS Hash:** \`${{ matrix.susfs_resolved_hash }}\` | |
| EOF | |
| fi | |
| if [ "${{ steps.build.outcome }}" = "success" ]; then | |
| cat >> $GITHUB_STEP_SUMMARY << EOF | |
| | Metric | Value | | |
| |--------|-------| | |
| | **Kernel** | ${{ steps.build.outputs.kernel_version }} | | |
| EOF | |
| if [ "${{ matrix.ksu_type }}" = "KSUN" ]; then | |
| cat >> $GITHUB_STEP_SUMMARY << EOF | |
| | **KSU Next** | v${{ steps.build.outputs.ksu_version }} | | |
| EOF | |
| else | |
| cat >> $GITHUB_STEP_SUMMARY << EOF | |
| | **KSU** | v${{ steps.build.outputs.ksu_version }} | | |
| EOF | |
| fi | |
| if [ "${{ matrix.susfs }}" = true ]; then | |
| cat >> $GITHUB_STEP_SUMMARY << EOF | |
| | **SUSFS** | ${{ steps.build.outputs.susfs_version }} | | |
| EOF | |
| fi | |
| cat >> $GITHUB_STEP_SUMMARY << EOF | |
| | **Build Time** | ${{ steps.build.outputs.build_time }}s | | |
| EOF | |
| if [ "${{ inputs.clean_build }}" != "true" ]; then | |
| cat >> $GITHUB_STEP_SUMMARY << EOF | |
| | **ccache Hit Rate** | ${{ steps.build.outputs.ccache_hit_rate }} | | |
| | **ccache Direct Rate** | ${{ steps.build.outputs.ccache_direct_rate }} | | |
| EOF | |
| fi | |
| if [ -n "${{ steps.build.outputs.warnings }}" ]; then | |
| echo "| **Warnings** | ${{ steps.build.outputs.warnings }} |" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| cat >> $GITHUB_STEP_SUMMARY << EOF | |
| **SHA256:** \`${{ steps.build.outputs.image_sha256 }}\` | |
| EOF | |
| fi | |
| - name: 🧹 Final cleanup and space report | |
| if: always() | |
| run: | | |
| echo "::group::Cleanup" | |
| # Remove build artifacts but PRESERVE ccache | |
| sudo rm -rf "$GITHUB_WORKSPACE/out" || true | |
| sudo rm -rf "$GITHUB_WORKSPACE/build" || true | |
| sudo rm -rf "$GITHUB_WORKSPACE/kernel/out" || true | |
| sudo rm -rf "$GITHUB_WORKSPACE/.repo" || true | |
| sudo rm -rf /tmp/* || true | |
| # Show ccache stats (don't clear it!) | |
| if command -v ccache >/dev/null 2>&1; then | |
| echo "" | |
| echo "📊 ccache statistics after build:" | |
| ccache -s | |
| echo "" | |
| echo "💾 ccache preserved for next build" | |
| fi | |
| echo "" | |
| echo "💽 Final disk usage:" | |
| df -h / | |
| echo "::endgroup::" | |
| trigger-release: | |
| needs: [set-op-model, build] | |
| runs-on: ubuntu-latest | |
| if: ${{ inputs.make_release }} | |
| env: | |
| REPO_OWNER: ${{ github.repository_owner }} | |
| REPO_NAME: ${{ github.event.repository.name }} | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| SUSFS_BASE_VERSION: ${{ needs.set-op-model.outputs.susfs_base_version }} | |
| RELEASE_NAME: '*TEST BUILD* OnePlus Kernels With KernelSU Next & SUSFS ${{ needs.set-op-model.outputs.susfs_base_version }} *TEST BUILD*' | |
| steps: | |
| - name: 📥 Checkout code | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: 🏷️ Generate and Create New Tag | |
| run: | | |
| # Only search for tags starting with this SUSFS version | |
| LATEST_MATCHING_TAG=$(gh api repos/$REPO_OWNER/$REPO_NAME/tags \ | |
| --jq "[.[] | select(.name | startswith(\"${SUSFS_BASE_VERSION}-r\"))] \ | |
| | sort_by(.name | split(\"-r\")[1] | tonumber) \ | |
| | last | .name // empty") | |
| if [ -z "$LATEST_MATCHING_TAG" ]; then | |
| # No existing release for this version SUSFS → first release | |
| NEW_TAG="${SUSFS_BASE_VERSION}-r1" | |
| else | |
| # Only increment the -r* suffix of the latest release for this version | |
| NEW_TAG=$(echo "$LATEST_MATCHING_TAG" | awk -F'-r' '{printf "%s-r%d", $1, $2+1}') | |
| fi | |
| echo "New tag: $NEW_TAG" | |
| echo "NEW_TAG=${NEW_TAG}" >> $GITHUB_ENV | |
| git tag $NEW_TAG | |
| git push origin $NEW_TAG | |
| - name: 📥 Download Artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| path: ./downloaded-artifacts | |
| merge-multiple: true | |
| skip-decompress: true | |
| - name: 📝 Generate Device List and Final Release Notes | |
| id: generate-notes | |
| run: | | |
| echo "=== Start building the release notes ===" | |
| # Collect build metadata | |
| declare -A device_info | |
| JSON_BUILD_DATA=$(jq -c '.' ./downloaded-artifacts/matrix.json) | |
| for file in $(find downloaded-artifacts -maxdepth 1 -name "*.zip" -type f | sort); do | |
| if [ -f "$file" ]; then | |
| zipname=$(basename "$file" .zip) | |
| rest="${zipname#AK3_}" | |
| IFS='_' read -ra parts <<< "$rest" | |
| model="${parts[0]}" | |
| os_version="${parts[1]}" | |
| kernel_version="${parts[2]}" | |
| ksu_type="${parts[3]}" | |
| ksu_ver="${parts[4]}" | |
| if [ "${parts[5]:-}" = "SuSFS" ]; then | |
| susfs_ver="${parts[6]:-unknown}" | |
| else | |
| susfs_ver="none" | |
| fi | |
| full_model="${model}_${os_version}" | |
| device_info["$full_model"]="$model|$os_version|$kernel_version|$ksu_type|$ksu_ver|$susfs_ver" | |
| fi | |
| done | |
| ksu_type="${{ fromJSON(needs.set-op-model.outputs.ksu_options_normalized)[0].type }}" | |
| ksu_ref="${{ fromJSON(needs.set-op-model.outputs.ksu_options_normalized)[0].hash }}" | |
| ksu_resolved_hash="${{ needs.set-op-model.outputs.ksu_resolved_hash }}" | |
| OPTIMIZE_LEVEL="${{ inputs.optimize_level }}" | |
| CLEAN_BUILD="${{ inputs.clean_build }}" | |
| # Hash map for GKI version | |
| declare -A susfs_map=( | |
| ["android12-5.10"]="${{ needs.set-op-model.outputs.susfs_hash_android12_5_10 }}" | |
| ["android13-5.15"]="${{ needs.set-op-model.outputs.susfs_hash_android13_5_15 }}" | |
| ["android14-6.1"]="${{ needs.set-op-model.outputs.susfs_hash_android14_6_1 }}" | |
| ["android15-6.6"]="${{ needs.set-op-model.outputs.susfs_hash_android15_6_6 }}" | |
| ["android16-6.12"]="${{ needs.set-op-model.outputs.susfs_hash_android16_6_12 }}" | |
| ) | |
| # List of GKI versions present in this run | |
| IFS=',' read -ra active_gki_keys \ | |
| <<< "${{ needs.set-op-model.outputs.active_gki_keys }}" | |
| cat << EOF > release_notes.md | |
| # 🎯 OnePlus Kernels with KernelSU Next & SUSFS $SUSFS_BASE_VERSION | |
| > **Build Date:** $(date -u '+%Y-%m-%d %H:%M:%S UTC') | |
| > **Build ID:** \`${{ github.run_id }}\` | |
| > **Workflow:** [\`${{ github.workflow }}\`](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) | |
| --- | |
| ## 📦 Built Devices (${#device_info[@]} total) | |
| | Model | OS Version | Kernel Version | Features | | |
| |-------|------------|----------------|----------| | |
| EOF | |
| for full_key in $(printf '%s\n' "${!device_info[@]}" | sort); do | |
| IFS='|' read -r model os_ver kernel_ver _ _ _ <<< "${device_info[$full_key]}" | |
| # Use jq to extract feature flags for this model from the JSON matrix | |
| feature_flags=$(jq -r --arg MODEL "$model" ' | |
| .[] | | |
| select(.model == $MODEL) | | |
| "\(.hmbird // false)\t\(.susfs // false)\t\(.bbr // false)\t\(.bbg // false)\t\(.ttl // false)\t\(.ip_set // false)\t\(.unicode // false)" | |
| ' <<< "$JSON_BUILD_DATA") | |
| features="" | |
| # If no match found, skip or handle error | |
| if [[ -z "$feature_flags" ]]; then | |
| echo "Warning: No JSON entry found for model: $model" >&2 | |
| else | |
| IFS=$'\t' read -r hmbird susfs bbr bbg ttl ip_set unicode <<< "$feature_flags" | |
| # Build features string based on boolean values | |
| [[ "$hmbird" == "true" ]] && features+="🐦 HMBIRD " | |
| [[ "$susfs" == "true" ]] && features+="ඞ SusFS " | |
| [[ "$bbr" == "true" ]] && features+="🚀 BBR " | |
| [[ "$bbg" == "true" ]] && features+="🛡️ BBG " | |
| [[ "$ttl" == "true" ]] && features+="🌐 TTL " | |
| [[ "$ip_set" == "true" ]] && features+="🧱 IP_SET & IPv6 NAT" | |
| [[ "$unicode" == "true" ]] && features+="🔧 Unicode Fix" | |
| fi | |
| printf "| %-13s | %-10s | %-16s | %-30s |\n" \ | |
| "$model" "$os_ver" "$kernel_ver" "$features" >> release_notes.md | |
| done | |
| if [ ${#device_info[@]} -gt 0 ]; then | |
| first_entry=$(printf '%s\n' "${!device_info[@]}" | sort | head -n1) | |
| IFS='|' read -r _ _ _ _ ksu_ver_global _ <<< "${device_info[$first_entry]}" | |
| else | |
| echo "::error::No device info found!" >&2 | |
| exit 1 | |
| fi | |
| cat << EOF >> release_notes.md | |
| --- | |
| ## 🔧 Build Configuration | |
| | Component | Version/Setting | | |
| |-----------|----------------| | |
| EOF | |
| # Display function: hash → direct hash, branch → branch (hash) | |
| ksu_display_value() { | |
| local input="$1" | |
| local resolved="$2" | |
| if [[ "$input" =~ ^[0-9a-f]{40}$ ]]; then | |
| echo "$input" | |
| else | |
| echo "$input ($resolved)" | |
| fi | |
| } | |
| ksu_display=$(ksu_display_value "$ksu_ref" "$ksu_resolved_hash") | |
| if [ "$ksu_type" == "KSUN" ]; then | |
| cat << EOF >> release_notes.md | |
| | **KernelSU Next Branch** | \`$ksu_display\` | | |
| | **KernelSU Next Version** | \`$ksu_ver_global\` | | |
| EOF | |
| elif [ "$ksu_type" == "KSU" ]; then | |
| cat << EOF >> release_notes.md | |
| | **KernelSU Branch** | \`$ksu_display\` | | |
| | **KernelSU Version** | \`$ksu_ver_global\` | | |
| EOF | |
| else | |
| cat << EOF >> release_notes.md | |
| | **Unknown KernelSU Fork Branch** | \`\` | | |
| | **Unknown KernelSU Fork Version** | \`\` | | |
| EOF | |
| fi | |
| cat << EOF >> release_notes.md | |
| | **SUSFS Version** | \`$SUSFS_BASE_VERSION\` | | |
| | **Optimization Level** | \`$OPTIMIZE_LEVEL\` | | |
| | **Clean Build** | $( [ "$CLEAN_BUILD" = "true" ] && echo "✅ Yes (no ccache)" || echo "❌ No (ccache enabled)" ) | | |
| | **Compiler** | Clang (version varies by device) | | |
| ### 📌 SUSFS Branch Mapping | |
| | Kernel Version | SUSFS Commit | | |
| |----------------|--------------| | |
| $(for key in "${active_gki_keys[@]}"; do | |
| echo "| $key | \`${susfs_map[$key]:-unknown}\` |" | |
| done) | |
| --- | |
| ## ✨ Features & Capabilities | |
| ### 🔐 Root Management | |
| EOF | |
| if [ "$ksu_type" == "KSUN" ]; then | |
| cat << EOF >> release_notes.md | |
| - **KernelSU Next** - Next-generation kernel-level root solution | |
| EOF | |
| elif [ "$ksu_type" == "KSU" ]; then | |
| cat << EOF >> release_notes.md | |
| - **KernelSU** - Kernel-level root solution | |
| EOF | |
| fi | |
| cat << EOF >> release_notes.md | |
| - **SUSFS $SUSFS_BASE_VERSION** - Advanced hiding and security features | |
| EOF | |
| if [ "$ksu_type" == "KSUN" ] && [ "${ksu_ver_global:-0}" -lt 12884 ]; then | |
| cat << EOF >> release_notes.md | |
| - **Magic Mount Support** - Seamless file system modifications | |
| EOF | |
| fi | |
| if [ "${ksu_ver_global:-0}" -lt 12884 ]; then | |
| cat << EOF >> release_notes.md | |
| - **Manual Hooks** - scope_min_manual_hooks_v1.4 for better compatibility | |
| EOF | |
| fi | |
| cat << EOF >> release_notes.md | |
| ### 🛡️ Security & Privacy | |
| - **Baseband Guard (BBG)** - LSM-based baseband security | |
| - **SUSFS Hide Features**: | |
| - ✅ SUS_PATH - Hide suspicious paths | |
| - ✅ SUS_MOUNT - Hide mount points (No Cli Support) | |
| - ✅ SUS_KSTAT - Spoof kernel statistics | |
| - ✅ SPOOF_UNAME - Kernel version spoofing | |
| - ✅ SPOOF_CMDLINE - Boot parameters spoofing | |
| - ✅ OPEN_REDIRECT - File access redirection | |
| - ✅ SUS_MAP - Memory mapping protection | |
| - ✅ AVC_SPOOF - Spoof Procfs avc denial logs | |
| - **Ptrace Leak Fix** - For kernels < 5.16 | |
| - **Unicode Fix** - Prevent path traversal and other detections using non-printable Unicode codepoints [Experimental] | |
| ### 🚀 Performance & Networking | |
| - **BBRv1** - Improved TCP congestion control | |
| - **Wireguard** - Built-in VPN support | |
| - **IP Set & IPv6 NAT Support** - Advanced firewall capabilities and IPv6 NAT Support | |
| - **TTL Target Support** - Network packet manipulation | |
| - **LTO (Link Time Optimization)** - Optimized binary size and performance | |
| - **ccache-accelerated builds** - Faster compilation times | |
| - **Optimisation Patches** - Memory, I/O, CPU scheduler, network and other general tunings | |
| ### 🔧 System Features | |
| - **TMPFS_XATTR** - Extended attributes for tmpfs (Mountify support) | |
| - **TMPFS_POSIX_ACL** - POSIX ACLs for tmpfs | |
| - **HMBIRD SCX** - Scheduler extensions for all SM8750/MT6991 devices | |
| --- | |
| ## 📱 Manager Applications | |
| ### Official Manager | |
| EOF | |
| if [ "$ksu_type" == "KSUN" ]; then | |
| cat << EOF >> release_notes.md | |
| - **KernelSU Next Manager** | |
| → [GitHub Release](https://github.com/KernelSU-Next/KernelSU-Next/releases) | |
| EOF | |
| elif [ "$ksu_type" == "KSU" ]; then | |
| cat << EOF >> release_notes.md | |
| - **KernelSU Manager** | |
| → [GitHub Release](https://github.com/tiann/KernelSU/releases) | |
| EOF | |
| fi | |
| cat << EOF >> release_notes.md | |
| ### Community Managers | |
| - **WildKSU Manager** (Recommended for additional features) | |
| → [GitHub Release](https://github.com/WildKernels/Wild_KSU/releases) | |
| ### Required Module | |
| - **KSU SUSFS Module** (Required for SUSFS features) | |
| → [GitHub Release](https://github.com/sidex15/ksu_module_susfs/releases) | |
| ### Recomended Flasher | |
| - **Kernel Flasher** (Required for flashing AnyKernel3 zips and backups and OTA) | |
| → [GitHub Release](https://github.com/fatalcoder524/KernelFlasher/releases) | |
| --- | |
| ## 📥 Installation Instructions | |
| ### Prerequisites | |
| - Unlocked bootloader. | |
| - Backup your current boot image. | |
| - Have root access using Magisk / KernelSU / Apatch (Any forks). | |
| ### Via Kernel Flasher | |
| 1. Download the appropriate ZIP for your device. | |
| 2. Flash the ZIP file to active slot using Kernel Flasher. | |
| 3. Based on root method, follow the steps: | |
| a. If root access is from Magisk(any forks): Perform complete uninstall from Magisk Manager. | |
| b. If root access is from KSU LKM(any forks): Flash Stock boot/init_boot/vendor_boot based on what you image you patched to get root access or Uninstall LKM. Recommended to flash stock image. | |
| c. If root access is from KSU GKI(any forks): Uninstall Manager. Delete /data/adb/ksud bin file. Reinstall Manager based on AK3 zip version. [Not required to do everytime] | |
| d. If root access is from Apatch(any forks): Delete all files from /data/adb. This is to start fresh and reduce multiple root implementation detected by modules. | |
| 4. Reboot system. | |
| 5. Install KernelSU-Next/WildSU Manager. | |
| 6. Install SusFS module from manager. | |
| --- | |
| ## 📜 Changelog | |
| ### This Release | |
| - Updated SUSFS to $SUSFS_BASE_VERSION. | |
| - Added HMBIRD support for all SM8750/MT6991 devices. | |
| - Improved ccache build system. | |
| - Enhanced SUSFS hiding capabilities. | |
| - Added IP_SET, IPv6 NAT and TTL support. | |
| - Added TMPFS_XATTR and TMPFS_POSIX_ACL support for Mountify. | |
| - Added Ptrace leak fix for kernels < 5.16. | |
| - Compiler optimizations (${{ inputs.optimize_level }}). | |
| - Additional General Optimisations. | |
| - Wild_KSU Manager Support. | |
| - Unicode Bypass Fix | |
| ### Previous Releases | |
| See [Releases Page](${{ github.server_url }}/${{ github.repository }}/releases) | |
| --- | |
| ## 🙏 Credits | |
| - **KernelSU Next Team** - Root solution | |
| - **KernelSU Team** - Root solution | |
| - **simonpunk** - SUSFS development | |
| - **OnePlus** - Kernel source code | |
| - **Community Contributors** - Testing and feedback | |
| --- | |
| **⚡ Built with ❤️ by the community** | |
| EOF | |
| echo "--- Final Release Notes ---" | |
| cat release_notes.md | |
| - name: 🚀 Create GitHub Release | |
| run: | | |
| gh release create "${{ env.NEW_TAG }}" \ | |
| --repo "${{ env.REPO_OWNER }}/${{ env.REPO_NAME }}" \ | |
| --title "${{ env.RELEASE_NAME }}" \ | |
| --notes-file release_notes.md \ | |
| --draft | |
| - name: 📤 Upload Release Assets Dynamically | |
| run: | | |
| for file in ./downloaded-artifacts/*.zip; do | |
| if [ -f "$file" ]; then | |
| echo "Uploading $file..." | |
| gh release upload "${{ env.NEW_TAG }}" "$file" --clobber | |
| fi | |
| done | |
| - name: 📊 Release summary | |
| if: success() | |
| run: | | |
| cat >> $GITHUB_STEP_SUMMARY << EOF | |
| --- | |
| ## 🎉 Release Created Successfully | |
| **Tag:** [\`${{ env.NEW_TAG }}\`](${{ github.server_url }}/${{ github.repository }}/releases/tag/${{ env.NEW_TAG }}) | |
| **Kernels:** $(find ./downloaded-artifacts -maxdepth 1 -name "*.zip" -type f | wc -l) | |
| ### 📦 Assets | |
| EOF | |
| for zip in ./downloaded-artifacts/*.zip; do | |
| if [ -f "$zip" ]; then | |
| name=$(basename "$zip") | |
| size=$(stat -c%s "$zip") | |
| size_mb=$(echo "scale=2; $size / 1024 / 1024" | bc) | |
| echo "- \`$name\` (${size_mb} MB)" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| done |