name: Build OpenWrt Packages on: push: branches: [main, master, develop] tags: - 'v*' pull_request: branches: [main, master] workflow_dispatch: inputs: package_name: description: 'Package to build (leave empty for all packages)' required: false type: choice options: - '' - 'luci-app-secubox' - 'luci-app-crowdsec-dashboard' - 'luci-app-netdata-dashboard' - 'luci-app-netifyd-dashboard' - 'luci-app-wireguard-dashboard' - 'luci-app-network-modes' - 'luci-app-client-guardian' - 'luci-app-system-hub' - 'luci-app-bandwidth-manager' - 'luci-app-auth-guardian' - 'luci-app-media-flow' - 'luci-app-vhost-manager' - 'luci-app-cdn-cache' openwrt_version: description: 'OpenWrt version' required: true default: '25.12.0-rc1' type: choice options: - '25.12.0-rc1' - '24.10.5' - '23.05.5' - '23.05.4' - 'SNAPSHOT' architectures: description: 'Architectures (comma-separated or "all")' required: false default: 'x86-64' env: OPENWRT_VERSION: ${{ github.event.inputs.openwrt_version || '25.12.0-rc1' }} permissions: contents: write jobs: # ============================================ # Setup and determine build matrix # ============================================ setup: runs-on: ubuntu-latest outputs: matrix: ${{ steps.set-matrix.outputs.matrix }} version: ${{ steps.version.outputs.version }} steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Determine version id: version run: | if [[ "${{ github.ref }}" == refs/tags/v* ]]; then VERSION="${{ github.ref_name }}" else VERSION="0.0.0-$(git rev-parse --short HEAD)" fi echo "version=${VERSION#v}" >> $GITHUB_OUTPUT echo "๐Ÿ“ฆ Package version: ${VERSION#v}" PACKAGE_NAME="${{ github.event.inputs.package_name }}" if [[ -n "$PACKAGE_NAME" ]]; then echo "๐ŸŽฏ Building single package: $PACKAGE_NAME" else echo "๐Ÿ“ฆ Building all packages" fi - name: Set build matrix id: set-matrix run: | cat > /tmp/matrix.json << 'EOF' { "include": [ { "target": "x86-64", "arch": "x86_64", "sdk_path": "x86/64", "description": "x86 64-bit (PC, VM)" }, { "target": "aarch64-cortex-a53", "arch": "aarch64_cortex-a53", "sdk_path": "mvebu/cortexa53", "description": "ARM Cortex-A53 (ESPRESSObin)" }, { "target": "aarch64-cortex-a72", "arch": "aarch64_cortex-a72", "sdk_path": "mvebu/cortexa72", "description": "ARM Cortex-A72 (MOCHAbin)" }, { "target": "aarch64-generic", "arch": "aarch64_generic", "sdk_path": "armsr/armv8", "description": "ARM 64-bit generic" }, { "target": "mips-24kc", "arch": "mips_24kc", "sdk_path": "ath79/generic", "description": "MIPS 24Kc (TP-Link)" }, { "target": "mipsel-24kc", "arch": "mipsel_24kc", "sdk_path": "ramips/mt7621", "description": "MIPS LE (Xiaomi, GL.iNet)" }, { "target": "mediatek-filogic", "arch": "aarch64_cortex-a53", "sdk_path": "mediatek/filogic", "description": "MediaTek Filogic" }, { "target": "rockchip-armv8", "arch": "aarch64_generic", "sdk_path": "rockchip/armv8", "description": "Rockchip (NanoPi R4S)" }, { "target": "bcm27xx-bcm2711", "arch": "aarch64_cortex-a72", "sdk_path": "bcm27xx/bcm2711", "description": "Raspberry Pi 4" } ] } EOF INPUT_ARCHS="${{ github.event.inputs.architectures }}" if [[ -z "$INPUT_ARCHS" || "$INPUT_ARCHS" == "all" ]]; then MATRIX=$(cat /tmp/matrix.json) else MATRIX=$(jq -c --arg archs "$INPUT_ARCHS" ' .include |= map(select(.target as $t | $archs | split(",") | map(gsub("^\\s+|\\s+$";"")) | any(. == $t))) ' /tmp/matrix.json) fi echo "matrix<> $GITHUB_OUTPUT echo "$MATRIX" >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT echo "๐Ÿ“‹ Build matrix:" echo "$MATRIX" | jq '.' # ============================================ # Build packages # ============================================ build: needs: setup runs-on: ubuntu-latest strategy: fail-fast: false matrix: ${{ fromJson(needs.setup.outputs.matrix) }} name: Build ${{ matrix.target }} steps: - name: Checkout source uses: actions/checkout@v4 - name: Free disk space run: | echo "๐Ÿงน Cleaning up disk space..." sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc /opt/hostedtoolcache/CodeQL sudo docker image prune --all --force df -h - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y \ build-essential clang flex bison g++ gawk \ gcc-multilib g++-multilib gettext git libncurses5-dev \ libssl-dev python3-setuptools python3-dev rsync \ swig unzip zlib1g-dev file wget curl jq ninja-build - name: Cache OpenWrt SDK uses: actions/cache@v4 id: cache-sdk with: path: sdk key: openwrt-sdk-${{ env.OPENWRT_VERSION }}-${{ matrix.target }}-v4 - name: Download OpenWrt SDK if: steps.cache-sdk.outputs.cache-hit != 'true' run: | echo "๐Ÿ“ฅ Downloading SDK for ${{ matrix.description }}..." BASE_URL="https://downloads.openwrt.org/releases/${{ env.OPENWRT_VERSION }}/targets/${{ matrix.sdk_path }}" # Find SDK filename with retry for attempt in 1 2 3; do echo "Attempt $attempt: Fetching SDK list..." SDK_FILE=$(curl -sL --retry 3 --retry-delay 5 "$BASE_URL/" | grep -oP 'openwrt-sdk[^"<>]+\.tar\.(xz|zst)' | head -1) && break sleep 10 done if [[ -z "$SDK_FILE" ]]; then echo "โŒ Could not find SDK" exit 1 fi echo "๐Ÿ“ฅ Downloading: $SDK_FILE" # Download with retry for attempt in 1 2 3; do echo "Download attempt $attempt..." wget -q --retry-connrefused --waitretry=5 --timeout=60 \ "${BASE_URL}/${SDK_FILE}" -O /tmp/sdk.tar.xz && break sleep 15 done # Extract mkdir -p sdk tar -xf /tmp/sdk.tar.xz -C sdk --strip-components=1 rm -f /tmp/sdk.tar.xz echo "โœ… SDK extracted" - name: Setup SDK feeds (GitHub mirrors) run: | cd sdk echo "๐Ÿ“ Configuring feeds with GitHub mirrors..." # FIRST: Remove unwanted feeds from feeds.conf.default to prevent indexing errors if [[ -f "feeds.conf.default" ]]; then sed -i '/telephony/d' feeds.conf.default sed -i '/routing/d' feeds.conf.default echo "โœ… Removed telephony and routing from feeds.conf.default" fi # Determine correct branch based on OpenWrt version VERSION="${{ env.OPENWRT_VERSION }}" if [[ "$VERSION" == "SNAPSHOT" ]]; then BRANCH="master" elif [[ "$VERSION" =~ ^25\. ]]; then BRANCH="openwrt-25.12" elif [[ "$VERSION" =~ ^24\. ]]; then BRANCH="openwrt-24.10" elif [[ "$VERSION" =~ ^23\. ]]; then BRANCH="openwrt-23.05" else BRANCH="openwrt-23.05" # fallback fi echo "๐Ÿ“Œ Using branch: $BRANCH for OpenWrt $VERSION" # Use GitHub mirrors - only essential feeds for SDK cat > feeds.conf << FEEDS src-git packages https://github.com/openwrt/packages.git;$BRANCH src-git luci https://github.com/openwrt/luci.git;$BRANCH FEEDS echo "๐Ÿ“‹ feeds.conf:" cat feeds.conf echo "" # Update feeds individually with error handling echo "๐Ÿ”„ Updating feeds..." FEEDS_OK=0 REQUIRED_FEEDS=2 for feed in packages luci; do echo "" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "Updating feed: $feed" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" FEED_SUCCESS=0 for attempt in 1 2 3; do echo "Attempt $attempt of 3..." if ./scripts/feeds update $feed 2>&1 | tee feed-update-${feed}.log; then if [[ -d "feeds/$feed" ]]; then echo " โœ… $feed updated successfully" FEEDS_OK=$((FEEDS_OK + 1)) FEED_SUCCESS=1 break else echo " โš ๏ธ Feed directory not created, retrying..." fi else echo " โš ๏ธ Update command failed, retrying..." fi sleep $((10 * attempt)) done if [[ $FEED_SUCCESS -eq 0 ]]; then echo " โŒ Failed to update $feed after 3 attempts" echo "Last attempt log:" tail -20 feed-update-${feed}.log 2>/dev/null || echo "No log available" fi done echo "" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "๐Ÿ“Š Feeds Status: $FEEDS_OK/$REQUIRED_FEEDS updated" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" # Verify feeds exist before continuing if [[ $FEEDS_OK -lt $REQUIRED_FEEDS ]]; then echo "" echo "โŒ ERROR: Not all required feeds were updated successfully" echo "SDK feeds directory contents:" ls -la feeds/ || echo "feeds directory doesn't exist" exit 1 fi # Install feeds echo "" echo "๐Ÿ“ฆ Installing feeds..." if ! ./scripts/feeds install -a 2>&1 | tee feed-install.log; then echo "โš ๏ธ Feed installation had errors, checking if critical..." # Continue anyway as some warnings are normal fi # Verify critical directories exist echo "" echo "๐Ÿ” Verifying feed installation..." for feed in packages luci; do if [[ -d "feeds/$feed" ]]; then FEED_SIZE=$(du -sh "feeds/$feed" 2>/dev/null | cut -f1) echo " โœ… feeds/$feed exists ($FEED_SIZE)" else echo " โŒ feeds/$feed is missing!" exit 1 fi done # Verify luci.mk exists if [[ -f "feeds/luci/luci.mk" ]]; then echo "โœ… luci.mk found" else echo "โš ๏ธ Creating fallback luci.mk..." mkdir -p feeds/luci cat > feeds/luci/luci.mk << 'LUCI_MK' # Minimal LuCI build system fallback LUCI_PKGARCH:=all define Package/Default SECTION:=luci CATEGORY:=LuCI SUBMENU:=3. Applications PKGARCH:=all endef LUCI_MK fi # Final cleanup of unwanted feeds (if somehow they still got created) rm -f feeds/telephony.index feeds/routing.index 2>/dev/null || true rm -rf feeds/telephony feeds/routing 2>/dev/null || true make defconfig echo "โœ… SDK configured" - name: Copy packages to SDK run: | VERSION="${{ needs.setup.outputs.version }}" PACKAGE_NAME="${{ github.event.inputs.package_name }}" if [[ -n "$PACKAGE_NAME" ]]; then echo "๐Ÿ“ฆ Copying single package: $PACKAGE_NAME (version: $VERSION)..." if [[ -d "$PACKAGE_NAME" && -f "${PACKAGE_NAME}/Makefile" ]]; then echo " ๐Ÿ“ $PACKAGE_NAME" cp -r "$PACKAGE_NAME" sdk/package/ # Update version sed -i "s/PKG_VERSION:=.*/PKG_VERSION:=$VERSION/" "sdk/package/${PACKAGE_NAME}/Makefile" sed -i "s/PKG_RELEASE:=.*/PKG_RELEASE:=1/" "sdk/package/${PACKAGE_NAME}/Makefile" # Fix Makefile include path for SDK environment # Change from ../../luci.mk to $(TOPDIR)/feeds/luci/luci.mk sed -i 's|include.*luci\.mk|include $(TOPDIR)/feeds/luci/luci.mk|' "sdk/package/${PACKAGE_NAME}/Makefile" echo " โœ“ Fixed Makefile include path" else echo "โŒ Package $PACKAGE_NAME not found or missing Makefile" exit 1 fi else echo "๐Ÿ“ฆ Copying all packages (version: $VERSION)..." for pkg in luci-app-*/; do if [[ -d "$pkg" && -f "${pkg}Makefile" ]]; then PKG_NAME=$(basename "$pkg") echo " ๐Ÿ“ $PKG_NAME" cp -r "$pkg" sdk/package/ # Update version sed -i "s/PKG_VERSION:=.*/PKG_VERSION:=$VERSION/" "sdk/package/${PKG_NAME}/Makefile" sed -i "s/PKG_RELEASE:=.*/PKG_RELEASE:=1/" "sdk/package/${PKG_NAME}/Makefile" # Fix Makefile include path for SDK environment # Change from ../../luci.mk to $(TOPDIR)/feeds/luci/luci.mk sed -i 's|include.*luci\.mk|include $(TOPDIR)/feeds/luci/luci.mk|' "sdk/package/${PKG_NAME}/Makefile" echo " โœ“ Fixed Makefile include path" fi done fi echo "" echo "๐Ÿ“‹ Packages in SDK:" ls -d sdk/package/luci-app-*/ 2>/dev/null || echo "None" - name: Download pre-built LuCI dependencies run: | cd sdk echo "๐Ÿ“ฅ Downloading pre-built LuCI dependencies from OpenWrt repository..." echo "This avoids compiling lucihttp and cgi-io which fail in SDK environment" echo "" # OpenWrt package repository base URL VERSION="${{ env.OPENWRT_VERSION }}" ARCH="${{ matrix.arch }}" # Detect package format based on OpenWrt version if [[ "$VERSION" =~ ^25\. ]] || [[ "$VERSION" == "SNAPSHOT" ]]; then PKG_EXT="apk" else PKG_EXT="ipk" fi # Skip for RC versions as repos may not be stable if [[ "$VERSION" =~ -rc ]]; then echo "โš ๏ธ Skipping dependency download for RC version" echo "Note: Our SecuBox packages are PKGARCH:=all (scripts only)" echo "They will be built regardless of dependency availability" exit 0 fi REPO_BASE="https://downloads.openwrt.org/releases/${VERSION}/packages/${ARCH}" echo "Repository: $REPO_BASE" echo "Package format: .${PKG_EXT}" echo "" # Download problematic dependencies as binaries mkdir -p dl/luci-deps cd dl/luci-deps echo "Downloading LuCI core packages..." # Try to download package index (format depends on version) if [[ "$PKG_EXT" == "apk" ]]; then curl -sL "${REPO_BASE}/luci/APKINDEX.tar.gz" > apkindex_luci.tar.gz || true curl -sL "${REPO_BASE}/packages/APKINDEX.tar.gz" > apkindex_base.tar.gz || true else curl -sL "${REPO_BASE}/luci/Packages" > packages_luci.txt || true curl -sL "${REPO_BASE}/packages/Packages" > packages_base.txt || true fi # Download critical LuCI dependencies that fail to compile in SDK echo "Downloading lucihttp and related packages..." DEPS=("lucihttp" "cgi-io" "lua") for dep in "${DEPS[@]}"; do if [[ "$PKG_EXT" == "apk" ]]; then # For APK, try to extract package names from index echo "Looking for $dep packages..." curl -sL "${REPO_BASE}/luci/${dep}*.${PKG_EXT}" -o "${dep}.${PKG_EXT}" 2>/dev/null || true curl -sL "${REPO_BASE}/packages/${dep}*.${PKG_EXT}" -o "${dep}.${PKG_EXT}" 2>/dev/null || true else # For IPK, download from packages feed curl -sL "${REPO_BASE}/luci/${dep}_*.${PKG_EXT}" -o "${dep}.${PKG_EXT}" 2>/dev/null || true curl -sL "${REPO_BASE}/packages/${dep}*.${PKG_EXT}" -o "${dep}.${PKG_EXT}" 2>/dev/null || true fi done # Install downloaded packages into SDK for pkg in *.${PKG_EXT}; do if [[ -f "$pkg" && -s "$pkg" ]]; then echo " โœ“ Downloaded: $pkg" # Copy to SDK packages directory for installation cp "$pkg" ../../packages/ 2>/dev/null || true fi done cd ../.. echo "" echo "โœ… Dependency download completed" echo "Note: Our SecuBox packages are PKGARCH:=all (scripts only)" echo "They will be built regardless of dependency availability" - name: Configure packages run: | cd sdk echo "โš™๏ธ Enabling packages..." for pkg in package/luci-app-*/; do if [[ -d "$pkg" ]]; then PKG_NAME=$(basename "$pkg") echo "CONFIG_PACKAGE_${PKG_NAME}=m" >> .config echo " โœ… $PKG_NAME" fi done # Enable download of pre-built packages for dependencies echo "CONFIG_DEVEL=y" >> .config echo "CONFIG_AUTOREBUILD=y" >> .config echo "CONFIG_AUTOREMOVE=y" >> .config echo "CONFIG_BUILDBOT=y" >> .config # Disable problematic packages that fail to compile in SDK # Our SecuBox packages are PKGARCH:=all (scripts) so they don't need these echo "# CONFIG_PACKAGE_lucihttp is not set" >> .config echo "# CONFIG_PACKAGE_cgi-io is not set" >> .config # Enable use of pre-built packages from feeds echo "CONFIG_FEED_packages=y" >> .config echo "CONFIG_FEED_luci=y" >> .config make defconfig - name: Build packages run: | cd sdk # Detect package format based on OpenWrt version VERSION="${{ env.OPENWRT_VERSION }}" if [[ "$VERSION" =~ ^25\. ]] || [[ "$VERSION" == "SNAPSHOT" ]]; then PKG_EXT="apk" echo "๐Ÿ“ฆ Building for OpenWrt $VERSION (apk format)" else PKG_EXT="ipk" echo "๐Ÿ“ฆ Building for OpenWrt $VERSION (ipk format)" fi # Export for later steps echo "PKG_EXT=$PKG_EXT" >> $GITHUB_ENV echo "" echo "๐Ÿ”จ Building SecuBox packages..." echo "" BUILT=0 FAILED=0 BUILT_LIST="" FAILED_LIST="" for pkg in package/luci-app-*/; do [[ -d "$pkg" ]] || continue PKG_NAME=$(basename "$pkg") echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "๐Ÿ“ฆ Building: $PKG_NAME" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" # Show package contents for debugging echo "๐Ÿ“ Package contents:" ls -la "$pkg" # Verify Makefile syntax if ! grep -q "BuildPackage" "${pkg}Makefile"; then echo "โš ๏ธ WARNING: Makefile missing BuildPackage call" fi # Build with timeout (10 minutes per package) BUILD_LOG="/tmp/build-${PKG_NAME}.log" # Our packages are PKGARCH:=all (pure scripts), no compilation needed # Try regular build first, fallback to direct packaging if dependencies fail if timeout 600 make package/${PKG_NAME}/compile V=s -j1 > "$BUILD_LOG" 2>&1; then # Build succeeded, check if package was created (.apk or .ipk) PKG_FILE=$(find bin -name "${PKG_NAME}*.${PKG_EXT}" 2>/dev/null | head -1) if [[ -n "$PKG_FILE" ]]; then echo "โœ… Built: $PKG_NAME" echo " โ†’ $PKG_FILE" BUILT=$((BUILT + 1)) BUILT_LIST="${BUILT_LIST}${PKG_NAME}," else echo "โš ๏ธ No .${PKG_EXT} generated for $PKG_NAME" echo "๐Ÿ“‹ Last 50 lines of build log:" tail -50 "$BUILD_LOG" FAILED=$((FAILED + 1)) FAILED_LIST="${FAILED_LIST}${PKG_NAME}," fi else echo "โŒ Build failed: $PKG_NAME" echo "๐Ÿ“‹ Last 100 lines of build log:" tail -100 "$BUILD_LOG" FAILED=$((FAILED + 1)) FAILED_LIST="${FAILED_LIST}${PKG_NAME}," fi echo "" done echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "๐Ÿ“Š Build Summary" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "โœ… Built: $BUILT packages (.${PKG_EXT})" echo "โŒ Failed: $FAILED packages" echo "" echo "Built: $BUILT_LIST" if [[ -n "$FAILED_LIST" ]]; then echo "Failed: $FAILED_LIST" fi - name: Collect artifacts id: collect run: | echo "๐Ÿ“ฆ Collecting artifacts..." PKG_EXT="${{ env.PKG_EXT }}" echo "๐Ÿ“ฆ Package format: .${PKG_EXT}" mkdir -p artifacts/${{ matrix.target }} # Find and copy package files (.apk or .ipk) find sdk/bin -name "luci-app-*.${PKG_EXT}" -exec cp {} artifacts/${{ matrix.target }}/ \; 2>/dev/null || true # Also collect any SecuBox related packages find sdk/bin -name "*secubox*.${PKG_EXT}" -exec cp {} artifacts/${{ matrix.target }}/ \; 2>/dev/null || true # Count packages PKG_COUNT=$(find artifacts/${{ matrix.target }} -name "*.${PKG_EXT}" 2>/dev/null | wc -l) echo "pkg_count=$PKG_COUNT" >> $GITHUB_OUTPUT echo "pkg_ext=$PKG_EXT" >> $GITHUB_OUTPUT echo "" echo "๐Ÿ“‹ Built packages for ${{ matrix.target }}:" ls -la artifacts/${{ matrix.target }}/ 2>/dev/null || echo "No packages" # Create checksums if [[ $PKG_COUNT -gt 0 ]]; then cd artifacts/${{ matrix.target }} sha256sum *.${PKG_EXT} > SHA256SUMS fi echo "" echo "๐Ÿ“ฆ Total: $PKG_COUNT packages (.${PKG_EXT})" - name: Upload artifacts uses: actions/upload-artifact@v4 if: steps.collect.outputs.pkg_count > 0 with: name: packages-${{ matrix.target }} path: artifacts/${{ matrix.target }}/ retention-days: 30 - name: Build Summary run: | PKG_COUNT="${{ steps.collect.outputs.pkg_count }}" PKG_EXT="${{ steps.collect.outputs.pkg_ext }}" echo "## ๐Ÿ“ฆ Build Results: ${{ matrix.target }}" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY echo "| Target | ${{ matrix.description }} |" >> $GITHUB_STEP_SUMMARY echo "| Architecture | ${{ matrix.arch }} |" >> $GITHUB_STEP_SUMMARY echo "| SDK Path | ${{ matrix.sdk_path }} |" >> $GITHUB_STEP_SUMMARY echo "| OpenWrt Version | ${{ env.OPENWRT_VERSION }} |" >> $GITHUB_STEP_SUMMARY echo "| Package Format | .$PKG_EXT |" >> $GITHUB_STEP_SUMMARY echo "| Packages Built | $PKG_COUNT |" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY if [[ "$PKG_COUNT" -gt 0 ]]; then echo "### Built Packages" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY ls artifacts/${{ matrix.target }}/*.$PKG_EXT 2>/dev/null | xargs -I{} basename {} | sort >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY fi # ============================================ # Publish combined artifacts (always) # ============================================ publish-artifacts: needs: [setup, build] runs-on: ubuntu-latest if: always() && needs.build.result == 'success' steps: - name: Download all artifacts uses: actions/download-artifact@v4 with: path: packages pattern: packages-* - name: Create combined archives run: | VERSION="${{ needs.setup.outputs.version }}" PACKAGE_NAME="${{ github.event.inputs.package_name }}" OPENWRT_VERSION="${{ env.OPENWRT_VERSION }}" mkdir -p release # Detect package format based on OpenWrt version if [[ "$OPENWRT_VERSION" =~ ^25\. ]] || [[ "$OPENWRT_VERSION" == "SNAPSHOT" ]]; then PKG_EXT="apk" else PKG_EXT="ipk" fi echo "๐Ÿ“ฆ Package format: .$PKG_EXT" # Determine prefix for archives if [[ -n "$PACKAGE_NAME" ]]; then PREFIX="${PACKAGE_NAME}" echo "๐Ÿ“ Creating archives for single package: $PACKAGE_NAME..." else PREFIX="secubox" echo "๐Ÿ“ Creating combined archives..." fi # Per-architecture archives for dir in packages/packages-*/; do [[ -d "$dir" ]] || continue ARCH=$(basename "$dir" | sed 's/packages-//') echo "๐Ÿ“ฆ $ARCH" # Copy package files (.apk or .ipk) to release mkdir -p "release/${ARCH}" cp "$dir"/*.$PKG_EXT "release/${ARCH}/" 2>/dev/null || true # Create archive if ls "release/${ARCH}"/*.$PKG_EXT >/dev/null 2>&1; then tar -czf "release/${PREFIX}-${VERSION}-${ARCH}.tar.gz" -C "release/${ARCH}" . fi done # Create all-in-one archive tar -czf "release/${PREFIX}-${VERSION}-all-architectures.tar.gz" -C packages . # Checksums cd release sha256sum *.tar.gz > SHA256SUMS 2>/dev/null || true echo "" echo "๐Ÿ“‹ Release contents:" ls -la echo "" echo "๐Ÿ“Š Package count per architecture:" for dir in */; do [[ -d "$dir" ]] || continue COUNT=$(ls "$dir"/*.$PKG_EXT 2>/dev/null | wc -l) echo " ${dir%/}: $COUNT packages" done - name: Upload combined release uses: actions/upload-artifact@v4 with: name: secubox-release-${{ needs.setup.outputs.version }} path: | release/*.tar.gz release/SHA256SUMS retention-days: 90 - name: Upload individual package files uses: actions/upload-artifact@v4 with: name: secubox-all-packages-${{ needs.setup.outputs.version }} path: | release/*/*.ipk release/*/*.apk retention-days: 90 # ============================================ # Create GitHub Release (on tags or manual) # ============================================ release: needs: [setup, build, publish-artifacts] runs-on: ubuntu-latest if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch' steps: - name: Checkout uses: actions/checkout@v4 - name: Download release artifact uses: actions/download-artifact@v4 with: name: secubox-release-${{ needs.setup.outputs.version }} path: release - name: Download all package files uses: actions/download-artifact@v4 with: name: secubox-all-packages-${{ needs.setup.outputs.version }} path: package-files continue-on-error: true - name: List packages id: list-packages run: | echo "๐Ÿ“ฆ Packages in release:" find . \( -name "*.ipk" -o -name "*.apk" \) -exec basename {} \; | sort -u # Count unique packages PKG_LIST=$(find . \( -name "*.ipk" -o -name "*.apk" \) -exec basename {} \; | sort -u | sed 's/_[0-9].*//g' | sed 's/-[0-9].*//g' | sort -u | tr '\n' ', ' | sed 's/,$//') echo "packages=$PKG_LIST" >> $GITHUB_OUTPUT - name: Create GitHub Release uses: softprops/action-gh-release@v2 with: name: ${{ github.event.inputs.package_name && format('{0} {1}', github.event.inputs.package_name, needs.setup.outputs.version) || format('SecuBox {0}', needs.setup.outputs.version) }} tag_name: ${{ startsWith(github.ref, 'refs/tags/') && github.ref_name || format('v{0}', needs.setup.outputs.version) }} body: | ## ๐Ÿ“ฆ ${{ github.event.inputs.package_name && format('{0} Package', github.event.inputs.package_name) || 'SecuBox Packages' }} v${{ needs.setup.outputs.version }} Pre-built LuCI package${{ github.event.inputs.package_name && '' || 's' }} for OpenWrt ${{ env.OPENWRT_VERSION }}. ${{ github.event.inputs.package_name && format('๐ŸŽฏ **Single package build**: {0}', github.event.inputs.package_name) || '' }} ### โœ… Built Packages ${{ steps.list-packages.outputs.packages }} ### ๐Ÿ“ฅ Installation **For OpenWrt 25.12+ (.apk format):** ```bash # Upload .apk files to router apk update apk add /tmp/luci-app-*.apk # Restart services /etc/init.d/rpcd restart ``` **For OpenWrt 24.10 and earlier (.ipk format):** ```bash # Upload .ipk files to router opkg update opkg install /tmp/luci-app-*.ipk # Restart services /etc/init.d/rpcd restart ``` ### ๐Ÿ—๏ธ Supported Architectures - `x86-64` - PC, VMs, Proxmox - `aarch64-cortex-a72` - MOCHAbin, RPi4 - `aarch64-cortex-a53` - ESPRESSObin - `aarch64-generic` - Generic ARM64 - `mips-24kc` - TP-Link, ath79 - `mipsel-24kc` - Xiaomi, GL.iNet - `mediatek-filogic` - MT7981/MT7986 ### ๐Ÿ”— Links - [SecuBox Website](https://secubox.cybermood.eu) - [CyberMind.fr](https://cybermind.fr) files: | release/*.tar.gz release/SHA256SUMS draft: false prerelease: ${{ github.event_name == 'workflow_dispatch' }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # ============================================ # Final Summary # ============================================ summary: needs: [setup, build] runs-on: ubuntu-latest if: always() steps: - name: Download artifacts uses: actions/download-artifact@v4 with: path: packages pattern: packages-* continue-on-error: true - name: Generate summary run: | PACKAGE_NAME="${{ github.event.inputs.package_name }}" echo "# ๐Ÿ“Š SecuBox Build Summary" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY echo "| Version | ${{ needs.setup.outputs.version }} |" >> $GITHUB_STEP_SUMMARY echo "| OpenWrt | ${{ env.OPENWRT_VERSION }} |" >> $GITHUB_STEP_SUMMARY echo "| Triggered by | ${{ github.event_name }} |" >> $GITHUB_STEP_SUMMARY if [[ -n "$PACKAGE_NAME" ]]; then echo "| Package | ๐ŸŽฏ $PACKAGE_NAME (single package build) |" >> $GITHUB_STEP_SUMMARY else echo "| Package | ๐Ÿ“ฆ All packages |" >> $GITHUB_STEP_SUMMARY fi echo "" >> $GITHUB_STEP_SUMMARY echo "## Build Results" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "| Architecture | Status | Packages |" >> $GITHUB_STEP_SUMMARY echo "|--------------|--------|----------|" >> $GITHUB_STEP_SUMMARY TOTAL=0 for dir in packages/packages-*/; do if [[ -d "$dir" ]]; then ARCH=$(basename "$dir" | sed 's/packages-//') COUNT=$(find "$dir" \( -name "*.ipk" -o -name "*.apk" \) 2>/dev/null | wc -l) TOTAL=$((TOTAL + COUNT)) if [[ $COUNT -gt 0 ]]; then echo "| $ARCH | โœ… Success | $COUNT |" >> $GITHUB_STEP_SUMMARY else echo "| $ARCH | โš ๏ธ Empty | 0 |" >> $GITHUB_STEP_SUMMARY fi fi done echo "" >> $GITHUB_STEP_SUMMARY echo "**Total packages built: $TOTAL**" >> $GITHUB_STEP_SUMMARY