secubox-openwrt/.github/workflows/build-openwrt-packages.yml
CyberMind-FR 39ca4af683 fix(ci): copy all Lua headers from source directory to fix lualib.h error
Enhanced Lua header installation in SDK to copy ALL .h files from the
Lua source directory, not just search for lua.h individually.

Changes:
- Primary: Copy all *.h files from feeds/packages/lang/lua/src/lua-*/
- Fallback 1: Find directory with lua.h in build_dir and copy ALL headers
- Fallback 2: Search for lua.h, lualib.h, lauxlib.h individually
- Added verification for all 3 critical headers

This fixes the lualib.h missing error that occurred even when lua.h
was successfully found and installed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-03 08:52:32 +01:00

1068 lines
39 KiB
YAML

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'
- 'secubox-app'
- 'luci-theme-secubox'
openwrt_version:
description: 'OpenWrt version'
required: true
default: '24.10.5'
type: choice
options:
- '24.10.5'
- '25.12.0-rc1'
- '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 || '24.10.5' }}
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<<EOF" >> $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
# Copy secubox-app
if [[ -d "package/secubox/secubox-app" ]]; then
echo " 📁 secubox-app"
mkdir -p sdk/package/secubox
cp -r package/secubox/secubox-app sdk/package/secubox/
# Update version
sed -i "s/PKG_VERSION:=.*/PKG_VERSION:=$VERSION/" "sdk/package/secubox/secubox-app/Makefile"
sed -i "s/PKG_RELEASE:=.*/PKG_RELEASE:=1/" "sdk/package/secubox/secubox-app/Makefile"
echo " ✓ Fixed version"
fi
# Copy luci-theme-secubox
if [[ -d "luci-theme-secubox" ]]; then
echo " 📁 luci-theme-secubox"
cp -r luci-theme-secubox sdk/package/
# Update version
sed -i "s/PKG_VERSION:=.*/PKG_VERSION:=$VERSION/" "sdk/package/luci-theme-secubox/Makefile"
sed -i "s/PKG_RELEASE:=.*/PKG_RELEASE:=1/" "sdk/package/luci-theme-secubox/Makefile"
# Fix Makefile include path for SDK environment
sed -i 's|include.*luci\.mk|include $(TOPDIR)/feeds/luci/luci.mk|' "sdk/package/luci-theme-secubox/Makefile"
echo " ✓ Fixed Makefile include path"
fi
fi
echo ""
echo "📋 Packages in SDK:"
ls -d sdk/package/luci-app-*/ sdk/package/secubox/secubox-app/ sdk/package/luci-theme-secubox/ 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: Install Lua headers in SDK staging directory
run: |
cd sdk
echo "📦 Installing Lua headers manually to prevent lucihttp compilation failures..."
# Install lua package to feeds
./scripts/feeds install lua
# Find Lua source directory in feeds
LUA_SRC=$(find feeds/packages/lang/lua/src -type d -name "lua-*" 2>/dev/null | head -1)
if [ -n "$LUA_SRC" ]; then
echo "Found Lua source at: $LUA_SRC"
# Create include directory in all target staging dirs
for STAGING in staging_dir/target-*; do
if [ -d "$STAGING" ]; then
echo "Installing headers to $STAGING/usr/include/"
mkdir -p "$STAGING/usr/include"
# Copy Lua headers
if [ -d "$LUA_SRC" ]; then
cp -v "$LUA_SRC"/*.h "$STAGING/usr/include/" 2>/dev/null || true
cp -v "$LUA_SRC"/src/*.h "$STAGING/usr/include/" 2>/dev/null || true
fi
fi
done
else
echo "⚠️ Lua source not found in feeds, trying alternative methods..."
# Alternative 1: Search for Lua headers in build_dir
LUA_BUILD_DIR=$(find build_dir -type f -name "lua.h" -printf '%h\n' 2>/dev/null | head -1)
if [ -n "$LUA_BUILD_DIR" ]; then
echo "Found Lua headers in build_dir at: $LUA_BUILD_DIR"
for STAGING in staging_dir/target-*; do
if [ -d "$STAGING" ]; then
mkdir -p "$STAGING/usr/include"
# Copy ALL header files from the directory
cp -v "$LUA_BUILD_DIR"/*.h "$STAGING/usr/include/" 2>/dev/null || true
fi
done
else
# Alternative 2: Use system Lua headers as last resort
echo "Searching for system Lua headers..."
for STAGING in staging_dir/target-*; do
if [ -d "$STAGING" ]; then
mkdir -p "$STAGING/usr/include"
# Try to find lua headers anywhere in the SDK
find . -type f \( -name "lua.h" -o -name "lualib.h" -o -name "lauxlib.h" \) \
-exec cp {} "$STAGING/usr/include/" \; 2>/dev/null || true
fi
done
fi
fi
# Verify headers are installed
echo ""
echo "Verifying Lua headers installation:"
for STAGING in staging_dir/target-*; do
HEADERS_FOUND=0
for HEADER in lua.h lualib.h lauxlib.h; do
if [ -f "$STAGING/usr/include/$HEADER" ]; then
echo "✅ $STAGING/usr/include/$HEADER"
HEADERS_FOUND=$((HEADERS_FOUND + 1))
else
echo "❌ $STAGING/usr/include/$HEADER NOT FOUND"
fi
done
if [ $HEADERS_FOUND -eq 3 ]; then
echo "✅ All required Lua headers installed for $(basename $STAGING)"
else
echo "⚠️ Warning: Missing some Lua headers in $(basename $STAGING)"
fi
done
- 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 secubox-app if present
if [[ -d "package/secubox/secubox-app" ]]; then
echo "CONFIG_PACKAGE_secubox-app=m" >> .config
echo " ✅ secubox-app"
fi
# Enable luci-theme-secubox if present
if [[ -d "package/luci-theme-secubox" ]]; then
echo "CONFIG_PACKAGE_luci-theme-secubox=m" >> .config
echo " ✅ luci-theme-secubox"
fi
# 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
# Use OpenWrt standard format for disabling packages
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
# Allow missing dependencies (our packages are standalone scripts)
echo "CONFIG_BROKEN=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
find sdk/bin -name "secubox-app*.${PKG_EXT}" -exec cp {} artifacts/${{ matrix.target }}/ \; 2>/dev/null || true
find sdk/bin -name "luci-theme-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